Client - add application configuration in Application Admin - #15
This commit is contained in:
@ -5,17 +5,27 @@ import { connect } from 'react-redux'
|
||||
import { setLoading } from '../../../actions/index'
|
||||
import { addActivity, editActivity } from '../../../actions/activities'
|
||||
import { history } from '../../../index'
|
||||
import { fileSizeLimit, gpxLimit, zipSizeLimit } from '../../../utils'
|
||||
import { getFileSize } from '../../../utils'
|
||||
import { translateSports } from '../../../utils/activities'
|
||||
|
||||
function FormWithGpx(props) {
|
||||
const { activity, loading, onAddActivity, onEditActivity, sports, t } = props
|
||||
const {
|
||||
activity,
|
||||
appConfig,
|
||||
loading,
|
||||
onAddActivity,
|
||||
onEditActivity,
|
||||
sports,
|
||||
t,
|
||||
} = props
|
||||
const sportId = activity ? activity.sport_id : ''
|
||||
const translatedSports = translateSports(sports, t, true)
|
||||
// prettier-ignore
|
||||
const zipTooltip =
|
||||
`${t('activities:no folder inside')}, ${gpxLimit} ${
|
||||
t('activities:files max')}, ${t('activities:max size')}: ${zipSizeLimit}`
|
||||
const zipTooltip = `${t('activities:no folder inside')}, ${
|
||||
appConfig.gpx_limit_import
|
||||
} ${t('activities:files max')}, ${t('activities:max size')}: ${getFileSize(
|
||||
appConfig.max_zip_file_size
|
||||
)}`
|
||||
const fileSizeLimit = getFileSize(appConfig.max_single_file_size)
|
||||
return (
|
||||
<form
|
||||
encType="multipart/form-data"
|
||||
@ -130,6 +140,7 @@ function FormWithGpx(props) {
|
||||
|
||||
export default connect(
|
||||
state => ({
|
||||
appConfig: state.application.config,
|
||||
loading: state.loading,
|
||||
}),
|
||||
dispatch => ({
|
||||
|
@ -3,15 +3,16 @@ import { Helmet } from 'react-helmet'
|
||||
|
||||
import AdminStats from './AdminStats'
|
||||
|
||||
export default function AdminDashboard() {
|
||||
export default function AdminDashboard(props) {
|
||||
const { t } = props
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>FitTrackee - Administration</title>
|
||||
<title>{t('administration:FitTrackee administration')}</title>
|
||||
</Helmet>
|
||||
<div className="card activity-card">
|
||||
<div className="card-header">
|
||||
<strong>FitTrackee administration</strong>
|
||||
<strong>{t('administration:FitTrackee administration')}</strong>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<AdminStats />
|
||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { withTranslation } from 'react-i18next'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { getAppStats } from '../../actions/stats'
|
||||
import { getAppData } from '../../actions/application'
|
||||
|
||||
class AdminStats extends React.Component {
|
||||
componentDidMount() {
|
||||
@ -80,7 +80,7 @@ export default withTranslation()(
|
||||
}),
|
||||
dispatch => ({
|
||||
loadAppStats: () => {
|
||||
dispatch(getAppStats())
|
||||
dispatch(getAppData('stats/all'))
|
||||
},
|
||||
})
|
||||
)(AdminStats)
|
||||
|
@ -0,0 +1,89 @@
|
||||
import React from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
||||
import Message from '../../Common/Message'
|
||||
import { history } from '../../../index'
|
||||
import { getFileSize } from '../../../utils'
|
||||
|
||||
export default function Config({ appConfig, message, t, updateIsInEdition }) {
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>
|
||||
FitTrackee - {t('administration:Application configuration')}
|
||||
</title>
|
||||
</Helmet>
|
||||
<Message message={message} t={t} />
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
{t('administration:Application configuration')}
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<table className="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{t('administration:Enable registration')}:
|
||||
</th>
|
||||
<td>
|
||||
{appConfig.registration
|
||||
? t('common:yes')
|
||||
: t('common:no')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{t('administration:Max. number of active users')}:
|
||||
</th>
|
||||
<td>{appConfig.max_users}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{t(
|
||||
'administration:Max. size of ' + 'uploaded files'
|
||||
)}
|
||||
:
|
||||
</th>
|
||||
<td>{getFileSize(appConfig.max_single_file_size)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{t('administration:Max. size of zip archive')}:
|
||||
</th>
|
||||
<td>{getFileSize(appConfig.max_zip_file_size)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
{t('administration:Max. files of zip archive')}:
|
||||
</th>
|
||||
<td>{appConfig.gpx_limit_import}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-primary btn-lg btn-block"
|
||||
onClick={() => updateIsInEdition()}
|
||||
value={t('common:Edit')}
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-secondary btn-lg btn-block"
|
||||
onClick={() => history.push('/admin')}
|
||||
value={t('common:Back')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
||||
import Message from '../../Common/Message'
|
||||
import { updateAppConfig } from '../../../actions/application'
|
||||
import { getFileSizeInMB } from '../../../utils'
|
||||
|
||||
class AdminApplication extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
formData: {},
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.initForm()
|
||||
}
|
||||
|
||||
initForm() {
|
||||
const { appConfig } = this.props
|
||||
const formData = {}
|
||||
Object.keys(appConfig).map(k =>
|
||||
appConfig[k] === null
|
||||
? (formData[k] = '')
|
||||
: ['max_single_file_size', 'max_zip_file_size'].includes(k)
|
||||
? (formData[k] = getFileSizeInMB(appConfig[k]))
|
||||
: (formData[k] = appConfig[k])
|
||||
)
|
||||
this.setState({ formData })
|
||||
}
|
||||
|
||||
handleFormChange(e) {
|
||||
const { formData } = this.state
|
||||
if (e.target.name === 'registration') {
|
||||
formData[e.target.name] = e.target.checked
|
||||
} else {
|
||||
formData[e.target.name] = +e.target.value
|
||||
}
|
||||
this.setState(formData)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
message,
|
||||
onHandleConfigFormSubmit,
|
||||
t,
|
||||
updateIsInEdition,
|
||||
} = this.props
|
||||
const { formData } = this.state
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>
|
||||
FitTrackee - {t('administration:Application configuration')}
|
||||
</title>
|
||||
</Helmet>
|
||||
{message && <Message message={message} t={t} />}
|
||||
{Object.keys(formData).length > 0 && (
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
{t('administration:Application configuration')}
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<form
|
||||
className="app-config-form"
|
||||
onSubmit={event => {
|
||||
event.preventDefault()
|
||||
onHandleConfigFormSubmit(formData)
|
||||
updateIsInEdition()
|
||||
}}
|
||||
>
|
||||
<div className="form-group row">
|
||||
<label
|
||||
className="col-sm-6 col-form-label"
|
||||
htmlFor="registration"
|
||||
>
|
||||
{t('administration:Enable registration')}:
|
||||
</label>
|
||||
<input
|
||||
className="col-sm-5"
|
||||
id="registration"
|
||||
name="registration"
|
||||
type="checkbox"
|
||||
checked={formData.registration}
|
||||
onChange={e => this.handleFormChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label
|
||||
className="col-sm-6 col-form-label"
|
||||
htmlFor="max_users"
|
||||
>
|
||||
{t('administration:Max. number of active users')}:
|
||||
</label>
|
||||
<input
|
||||
className="col-sm-5"
|
||||
id="max_users"
|
||||
name="max_users"
|
||||
type="number"
|
||||
min="0"
|
||||
value={formData.max_users}
|
||||
onChange={e => this.handleFormChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label
|
||||
className="col-sm-6 col-form-label"
|
||||
htmlFor="max_single_file_size"
|
||||
>
|
||||
{t(
|
||||
'administration:Max. size of uploaded files (in Mb)'
|
||||
)}
|
||||
:
|
||||
</label>
|
||||
<input
|
||||
className="col-sm-5"
|
||||
id="max_single_file_size"
|
||||
name="max_single_file_size"
|
||||
type="number"
|
||||
step="0.1"
|
||||
min="0"
|
||||
value={formData.max_single_file_size}
|
||||
onChange={e => this.handleFormChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label
|
||||
className="col-sm-6 col-form-label"
|
||||
htmlFor="max_zip_file_size"
|
||||
>
|
||||
{t('administration:Max. size of zip archive (in Mb)')}
|
||||
:
|
||||
</label>
|
||||
<input
|
||||
className="col-sm-5"
|
||||
id="max_zip_file_size"
|
||||
name="max_zip_file_size"
|
||||
type="number"
|
||||
step="0.1"
|
||||
min="0"
|
||||
value={formData.max_zip_file_size}
|
||||
onChange={e => this.handleFormChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label
|
||||
className="col-sm-6 col-form-label"
|
||||
htmlFor="gpx_limit_import"
|
||||
>
|
||||
{t('administration:Max. files of zip archive')}
|
||||
</label>
|
||||
<input
|
||||
className="col-sm-5"
|
||||
id="gpx_limit_import"
|
||||
name="gpx_limit_import"
|
||||
type="number"
|
||||
min="0"
|
||||
value={formData.gpx_limit_import}
|
||||
onChange={e => this.handleFormChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-primary btn-lg btn-block"
|
||||
value={t('common:Submit')}
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
className="btn btn-secondary btn-lg btn-block"
|
||||
onClick={() => updateIsInEdition()}
|
||||
value={t('common:Cancel')}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
() => ({}),
|
||||
dispatch => ({
|
||||
onHandleConfigFormSubmit: formData => {
|
||||
formData.max_single_file_size *= 1048576
|
||||
formData.max_zip_file_size *= 1048576
|
||||
dispatch(updateAppConfig(formData))
|
||||
},
|
||||
})
|
||||
)(AdminApplication)
|
54
fittrackee_client/src/components/Admin/Application/index.jsx
Normal file
54
fittrackee_client/src/components/Admin/Application/index.jsx
Normal file
@ -0,0 +1,54 @@
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
||||
import Config from './Config'
|
||||
import ConfigForm from './ConfigForm'
|
||||
import Message from '../../Common/Message'
|
||||
|
||||
class AdminApplication extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
isInEdition: false,
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { appConfig, message, t } = this.props
|
||||
const { isInEdition } = this.state
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>FitTrackee - {t('administration:Administration')}</title>
|
||||
</Helmet>
|
||||
{message && <Message message={message} t={t} />}
|
||||
{isInEdition ? (
|
||||
<ConfigForm
|
||||
appConfig={appConfig}
|
||||
message={message}
|
||||
updateIsInEdition={() => {
|
||||
this.setState({ isInEdition: false })
|
||||
}}
|
||||
t={t}
|
||||
/>
|
||||
) : (
|
||||
<Config
|
||||
appConfig={appConfig}
|
||||
message={message}
|
||||
t={t}
|
||||
updateIsInEdition={() => {
|
||||
this.setState({ isInEdition: true })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(state => ({
|
||||
appConfig: state.application.config,
|
||||
message: state.message,
|
||||
user: state.user,
|
||||
}))(AdminApplication)
|
@ -2,14 +2,13 @@ import React from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { withTranslation } from 'react-i18next'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link, Redirect, Route, Switch } from 'react-router-dom'
|
||||
import { Link, Route, Switch } from 'react-router-dom'
|
||||
|
||||
import AdminApplication from './Application'
|
||||
import AdminDashboard from './AdminDashboard'
|
||||
import AdminMenu from './AdminMenu'
|
||||
import AdminSports from './Sports'
|
||||
import AccessDenied from './../Others/AccessDenied'
|
||||
import NotFound from './../Others/NotFound'
|
||||
import { isLoggedIn } from '../../utils'
|
||||
|
||||
function Admin(props) {
|
||||
const { t, user } = props
|
||||
@ -19,47 +18,48 @@ function Admin(props) {
|
||||
<title>FitTrackee - {t('administration:Administration')}</title>
|
||||
</Helmet>
|
||||
<div className="container dashboard">
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<div className="card activity-card">
|
||||
<div className="card-header">
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/admin/',
|
||||
}}
|
||||
>
|
||||
{t('administration:Administration')}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<AdminMenu t={t} />
|
||||
{user.admin ? (
|
||||
<div className="row">
|
||||
<div className="col-md-3">
|
||||
<div className="card activity-card">
|
||||
<div className="card-header">
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/admin/',
|
||||
}}
|
||||
>
|
||||
{t('administration:Administration')}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<AdminMenu t={t} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-9">
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path="/admin"
|
||||
render={() => <AdminDashboard t={t} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/admin/application"
|
||||
render={() => <AdminApplication t={t} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/admin/sports"
|
||||
render={() => <AdminSports t={t} />}
|
||||
/>
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-9">
|
||||
{isLoggedIn() ? (
|
||||
user.admin ? (
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path="/admin"
|
||||
render={() => <AdminDashboard t={t} />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/admin/sports"
|
||||
render={() => <AdminSports t={t} />}
|
||||
/>
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
) : (
|
||||
<AccessDenied />
|
||||
)
|
||||
) : (
|
||||
<Redirect to="/login" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<NotFound />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -177,6 +177,10 @@ label {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.app-config-form label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card {
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Redirect, Route, Switch } from 'react-router-dom'
|
||||
|
||||
import './App.css'
|
||||
@ -14,13 +15,17 @@ import Profile from './User/Profile'
|
||||
import ProfileEdit from './User/ProfileEdit'
|
||||
import Statistics from './Statistics'
|
||||
import UserForm from './User/UserForm'
|
||||
import { getAppData } from '../actions/application'
|
||||
import { isLoggedIn } from '../utils'
|
||||
|
||||
export default class App extends React.Component {
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.props = props
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.loadAppConfig()
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
@ -74,7 +79,12 @@ export default class App extends React.Component {
|
||||
<Route exact path="/activities/history" component={Activities} />
|
||||
<Route exact path="/activities/statistics" component={Statistics} />
|
||||
<Route path="/activities" component={Activity} />
|
||||
<Route path="/admin" component={Admin} />
|
||||
<Route
|
||||
path="/admin"
|
||||
render={() =>
|
||||
isLoggedIn() ? <Admin /> : <UserForm formType={'login'} />
|
||||
}
|
||||
/>
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
<Footer />
|
||||
@ -82,3 +92,11 @@ export default class App extends React.Component {
|
||||
)
|
||||
}
|
||||
}
|
||||
export default connect(
|
||||
() => ({}),
|
||||
dispatch => ({
|
||||
loadAppConfig: () => {
|
||||
dispatch(getAppData('config'))
|
||||
},
|
||||
})
|
||||
)(App)
|
||||
|
@ -1,16 +1,24 @@
|
||||
import React from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
||||
export default function AccessDenied() {
|
||||
export default function AccessDenied(props) {
|
||||
const { t } = props
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>FitTrackee - Access denied</title>
|
||||
<title>FitTrackee - {t('Access denied')}</title>
|
||||
</Helmet>
|
||||
<h1 className="page-title">Access denied</h1>
|
||||
<p className="App-center">
|
||||
{"You don't have permissions to access this page."}
|
||||
</p>
|
||||
<div className="row">
|
||||
<div className="col-2" />
|
||||
<div className="card col-8">
|
||||
<div className="card-body">
|
||||
<div className="text-center">
|
||||
{t("You don't have permissions to access this page.")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-2" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
import React from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function NotFound() {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<title>fittrackee - 404</title>
|
||||
</Helmet>
|
||||
<h1 className="page-title">Page not found</h1>
|
||||
<h1 className="page-title">{t('Page not found')}</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
|
||||
import { Helmet } from 'react-helmet'
|
||||
|
||||
import { history } from '../../index'
|
||||
import { isRegistrationAllowed } from '../../utils'
|
||||
|
||||
export default function Form(props) {
|
||||
const { t } = useTranslation()
|
||||
@ -22,7 +21,7 @@ export default function Form(props) {
|
||||
<div className="col-md-6">
|
||||
<hr />
|
||||
<br />
|
||||
{props.formType === 'register' && !isRegistrationAllowed ? (
|
||||
{props.formType === 'register' && !props.isRegistrationAllowed ? (
|
||||
<div className="card">
|
||||
<div className="card-body">Registration is disabled.</div>
|
||||
<div className="card-body">
|
||||
|
@ -7,15 +7,23 @@ import { Link } from 'react-router-dom'
|
||||
|
||||
import Message from '../Common/Message'
|
||||
import { deletePicture, uploadPicture } from '../../actions/user'
|
||||
import { apiUrl, fileSizeLimit } from '../../utils'
|
||||
import { apiUrl, getFileSize } from '../../utils'
|
||||
|
||||
function Profile({ message, onDeletePicture, onUploadPicture, t, user }) {
|
||||
function Profile({
|
||||
appConfig,
|
||||
message,
|
||||
onDeletePicture,
|
||||
onUploadPicture,
|
||||
t,
|
||||
user,
|
||||
}) {
|
||||
const createdAt = user.created_at
|
||||
? format(new Date(user.created_at), 'dd/MM/yyyy HH:mm')
|
||||
: ''
|
||||
const birthDate = user.birth_date
|
||||
? format(new Date(user.birth_date), 'dd/MM/yyyy')
|
||||
: ''
|
||||
const fileSizeLimit = getFileSize(appConfig.max_single_file_size)
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
@ -118,6 +126,7 @@ function Profile({ message, onDeletePicture, onUploadPicture, t, user }) {
|
||||
export default withTranslation()(
|
||||
connect(
|
||||
state => ({
|
||||
appConfig: state.application.config,
|
||||
message: state.message,
|
||||
user: state.user,
|
||||
}),
|
||||
|
@ -42,6 +42,7 @@ class UserForm extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
formType,
|
||||
isRegistrationAllowed,
|
||||
message,
|
||||
messages,
|
||||
onHandleUserFormSubmit,
|
||||
@ -56,6 +57,7 @@ class UserForm extends React.Component {
|
||||
<div>
|
||||
<Message message={message} messages={messages} t={t} />
|
||||
<Form
|
||||
isRegistrationAllowed={isRegistrationAllowed}
|
||||
formType={formType}
|
||||
userForm={formData}
|
||||
onHandleFormChange={event => this.onHandleFormChange(event)}
|
||||
@ -73,6 +75,7 @@ class UserForm extends React.Component {
|
||||
export default withTranslation()(
|
||||
connect(
|
||||
state => ({
|
||||
isRegistrationAllowed: state.application.config.is_registration_enabled,
|
||||
location: state.router.location,
|
||||
message: state.message,
|
||||
messages: state.messages,
|
||||
|
Reference in New Issue
Block a user