Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Rex Dri
Rex Dri
Commits
7768f71e
Commit
7768f71e
authored
Sep 11, 2018
by
Florent Chehab
Browse files
userData handling changed followning the change in the backend
UniversitySemestersDates partially connected
parent
32e2b6bb
Pipeline
#27167
passed with stages
in 2 minutes and 44 seconds
Changes
8
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
backend/models/user/userData.py
View file @
7768f71e
...
...
@@ -38,7 +38,7 @@ class UserDataSerializer(MyModelSerializer):
class
UserDataViewSet
(
MyModelViewSet
):
permission_classes
=
get_viewset_permissions
(
"UserDataViewSet"
)
serializer_class
=
UserDataSerializer
BYPASS_DICT_MODE
=
True
LIST_SHOULD_BE_DETAIL
=
True
def
get_queryset
(
self
):
return
UserData
.
objects
.
filter
(
owner
=
self
.
request
.
user
)
# pylint: disable=E1101
frontend/generate/templates/actions.tpl
View file @
7768f71e
...
...
@@ -139,9 +139,9 @@ export function {{obj.name}}FetchDataSuccess({{obj.name}}) {
}
export function {
{
obj
.
name
}
}FetchData() {
export function {
{
obj
.
name
}
}FetchData(
pk=""
) {
return _FetchData(
""
,
pk
,
"{
{
obj
.
api_end_point
}
}",
{
{
obj
.
name
}
}IsLoading,
{
{
obj
.
name
}
}FetchDataSuccess,
...
...
frontend/src/components/MyComponent.js
View file @
7768f71e
...
...
@@ -3,28 +3,7 @@ import Loading from './other/Loading';
class
MyComponent
extends
Component
{
customErrorHandlers
=
{}
requireUserData
=
false
;
// If true,
// You need to import
// userDataElFetchData,
// userDataElSaveData,
//your mapStateToProps should contain:
// const mapStateToProps = (state) => {
// return {
// userDataEl: state.userDataEl
// }
// };
//
// And your mapDispatchToProps should have:
// const mapDispatchToProps = (dispatch) => {
// return {
// fetchUserDataSingle: (id) => dispatch(userDataElFetchData(id)),
// fetchData: {
// userDataEl: () => dispatch(userDataElFetchData("")),
// },
// createUserData: () => dispatch(userDataElSaveData(Object()))
// };
// };
idToUse
=
null
;
getFetchedData
(
prop
)
{
return
this
.
props
[
prop
].
fetched
.
data
;
...
...
@@ -79,6 +58,7 @@ class MyComponent extends Component {
if
(
prop
.
fetchHasError
.
status
)
{
if
(
prop_key
in
this
.
customErrorHandlers
)
{
console
.
log
(
"
icicicicici
"
);
return
this
.
customErrorHandlers
[
prop_key
](
prop
.
fetchHasError
.
error
);
}
else
{
return
true
;
}
...
...
@@ -113,13 +93,25 @@ class MyComponent extends Component {
if
(
prop
===
Object
(
prop
)
&&
'
fetched
'
in
prop
)
{
if
((
!
prop
.
fetched
.
fetchedAt
)
||
prop
.
invalidated
)
{
if
(
!
prop
.
isLoading
)
{
props
.
fetchData
[
prop_key
]();
if
(
this
.
idToUse
)
{
props
.
fetchData
[
prop_key
](
this
.
props
[
this
.
idToUse
]);
}
else
{
props
.
fetchData
[
prop_key
]();
}
}
}
}
}
}
allFetchedDataReady
(){
if
(
this
.
checkPropsHasError
()
||
this
.
checkPropsIsLoading
()
||
this
.
checkPropsInvalidated
()
||
this
.
checkPropsIsSaving
())
{
return
false
;
}
else
{
return
true
;
}
}
componentDidMount
()
{
this
.
loadPropsIfNeeded
();
this
.
myComponentDidMount
();
...
...
@@ -129,27 +121,6 @@ class MyComponent extends Component {
componentDidUpdate
()
{
// TODO ajouter expire date
this
.
loadPropsIfNeeded
();
if
(
this
.
requireUserData
)
{
//TODO cleaner too many loads
// load the correct user data
const
{
userDataEl
}
=
this
.
props
;
if
(
userDataEl
.
isLoading
||
userDataEl
.
isSaving
)
{
return
;
}
const
userData
=
this
.
getFetchedData
(
"
userDataEl
"
);
if
(
userData
instanceof
Array
)
{
if
(
userData
.
length
==
0
)
{
if
(
!
this
.
props
.
userDataEl
.
isSaving
)
{
this
.
props
.
createUserData
();
}
}
else
if
(
userData
.
length
==
1
)
{
this
.
props
.
fetchUserDataSingle
(
userData
[
0
].
id
)
}
else
{
throw
Error
(
"
We shouldn't have more thant one here !
"
)
}
}
}
this
.
myComponentDidUpdate
();
}
myComponentDidUpdate
()
{
};
...
...
@@ -159,7 +130,7 @@ class MyComponent extends Component {
return
<
p
>
Sorry
!
There
was
an
error
loading
the
items
<
/p>
;
}
if
(
this
.
checkPropsIsLoading
()
||
this
.
checkPropsInvalidated
()
||
this
.
checkPropsIsSaving
())
{
if
(
!
this
.
allFetchedDataReady
())
{
return
<
Loading
/>
;
}
...
...
frontend/src/components/ThemeProvider.js
View file @
7768f71e
...
...
@@ -17,40 +17,45 @@ import { saveAppTheme } from '../actions/theme';
class
ThemeProvider
extends
MyComponent
{
requireUserData
=
true
;
state
=
{
theme
:
this
.
props
.
themeSavedInTheApp
.
theme
};
myComponentDidUpdate
()
{
if
(
!
this
.
allFetchedDataReady
())
{
return
;
}
const
currentTheme
=
this
.
state
.
theme
;
const
themeSavedInTheApp
=
this
.
props
.
themeSavedInTheApp
.
theme
;
const
themeSavedInTheAppAt
=
this
.
props
.
themeSavedInTheApp
.
savedAt
;
le
t
themeOnServer
=
Object
()
;
le
t
themeOnServerRetrievedAt
=
0
;
cons
t
themeOnServer
=
this
.
props
.
userDataEl
.
fetched
.
data
.
config
.
theme
;
cons
t
themeOnServerRetrievedAt
=
this
.
props
.
userDataEl
.
fetched
.
fetchedAt
;
try
{
themeOnServer
=
this
.
props
.
userDataEl
.
fetched
.
data
.
config
.
theme
;
themeOnServerRetrievedAt
=
this
.
props
.
userDataEl
.
fetched
.
fetchedAt
;
}
catch
(
e
)
{
if
(
!
e
instanceof
TypeError
)
{
throw
e
;
}
if
(
!
themeOnServer
)
{
// config on server is raw, we need to add the default one.
const
userData
=
this
.
getFetchedData
(
'
userDataEl
'
)
;
let
newUserData
=
Object
.
assign
({},
userData
);
newUserData
.
config
.
theme
=
this
.
state
.
theme
;
this
.
props
.
saveUserData
(
newUserData
)
;
return
;
}
const
themeToRender
=
themeSavedInTheAppAt
>
themeOnServerRetrievedAt
?
themeSavedInTheApp
:
themeOnServer
;
if
((
!
areSameThemes
(
themeToRender
,
currentTheme
))
&&
typeof
themeToRender
!=
'
undefined
'
)
{
this
.
setState
({
theme
:
themeToRender
});
if
(
!
areSameThemes
(
themeToRender
,
themeSavedInTheApp
)){
if
(
!
areSameThemes
(
themeToRender
,
themeSavedInTheApp
))
{
this
.
props
.
saveTheme
(
themeToRender
);
}
}
}
myRender
()
{
const
font
=
{
typography
:
{
fontSize
:
14
,
htmlFontSize
:
14
}}
const
font
=
{
typography
:
{
fontSize
:
14
,
htmlFontSize
:
14
}
}
const
theme
=
Object
.
assign
({},
this
.
state
.
theme
,
font
)
return
(
<
div
>
...
...
@@ -74,11 +79,10 @@ const mapStateToProps = (state) => {
const
mapDispatchToProps
=
(
dispatch
)
=>
{
return
{
saveTheme
:
(
theme
)
=>
dispatch
(
saveAppTheme
(
theme
)),
fetch
UserData
Single
:
(
id
)
=>
dispatch
(
userDataEl
Fetch
Data
(
i
d
)),
save
UserData
:
(
data
)
=>
dispatch
(
userDataEl
Save
Data
(
d
ata
)),
fetchData
:
{
userDataEl
:
()
=>
dispatch
(
userDataElFetchData
(
""
)),
},
createUserData
:
()
=>
dispatch
(
userDataElSaveData
(
Object
()))
};
};
...
...
frontend/src/components/settings/ColorTools.js
View file @
7768f71e
...
...
@@ -76,7 +76,6 @@ const styles = theme => ({
// TODO switch to my component
class
ColorTool
extends
MyComponent
{
requireUserData
=
true
;
state
=
this
.
props
.
state
componentWillUnmount
()
{
...
...
@@ -90,29 +89,41 @@ class ColorTool extends MyComponent {
}
myComponentDidUpdate
()
{
if
(
!
this
.
allFetchedDataReady
())
{
return
}
try
{
const
themeOnServerRetrievedAt
=
this
.
props
.
userDataEl
.
fetched
.
fetchedAt
;
if
(
themeOnServerRetrievedAt
>
this
.
state
.
updatedAt
)
{
const
configOnServer
=
this
.
props
.
userDataEl
.
fetched
.
data
.
config
;
const
colorPickerConfigOnServer
=
configOnServer
.
colorPicker
;
const
themeOnServer
=
configOnServer
.
theme
;
// we need to set the color picker colors from server color
const
primary
=
themeOnServer
.
palette
.
primary
.
main
;
const
secondary
=
themeOnServer
.
palette
.
secondary
.
main
;
this
.
setState
({
updatedAt
:
Date
.
now
(),
primary
,
secondary
,
primaryHue
:
colorPickerConfigOnServer
.
primaryHue
,
secondaryHue
:
colorPickerConfigOnServer
.
secondaryHue
,
primaryShade
:
colorPickerConfigOnServer
.
primaryShade
,
secondaryShade
:
colorPickerConfigOnServer
.
secondaryShade
,
darkModeActivated
:
themeOnServer
.
palette
.
type
==
'
light
'
?
false
:
true
});
}
}
catch
(
e
)
{
if
(
!
(
e
instanceof
TypeError
))
{
throw
e
;
}
}
const
configOnServer
=
this
.
props
.
userDataEl
.
fetched
.
data
.
config
;
const
themeOnServer
=
configOnServer
.
theme
;
const
colorPickerConfigOnServer
=
configOnServer
.
colorPicker
;
const
serverDataRetrievedAt
=
this
.
props
.
userDataEl
.
fetched
.
fetchedAt
;
if
(
!
themeOnServer
)
{
// we need to initialize it
this
.
handleSendToServer
(
true
,
false
);
return
;
}
if
(
!
colorPickerConfigOnServer
)
{
this
.
handleSendToServer
(
false
,
true
);
return
;
}
if
(
serverDataRetrievedAt
>
this
.
state
.
updatedAt
)
{
// we need to set the color picker colors from server color
const
primary
=
themeOnServer
.
palette
.
primary
.
main
;
const
secondary
=
themeOnServer
.
palette
.
secondary
.
main
;
this
.
setState
({
updatedAt
:
Date
.
now
(),
primary
,
secondary
,
primaryHue
:
colorPickerConfigOnServer
.
primaryHue
,
secondaryHue
:
colorPickerConfigOnServer
.
secondaryHue
,
primaryShade
:
colorPickerConfigOnServer
.
primaryShade
,
secondaryShade
:
colorPickerConfigOnServer
.
secondaryShade
,
darkModeActivated
:
themeOnServer
.
palette
.
type
==
'
light
'
?
false
:
true
});
}
}
handleChangeHue
=
name
=>
event
=>
{
...
...
@@ -174,16 +185,20 @@ class ColorTool extends MyComponent {
return
currentTheme
;
}
handleSendToServer
=
()
=>
{
handleSendToServer
=
(
saveTheme
=
true
,
saveColorPicker
=
true
)
=>
{
const
userData
=
this
.
props
.
userDataEl
.
fetched
.
data
;
let
newUserData
=
Object
.
assign
({},
userData
);
newUserData
.
config
.
theme
=
this
.
getThemeFromProps
();
newUserData
.
config
.
colorPicker
=
{
primaryHue
:
this
.
state
.
primaryHue
,
secondaryHue
:
this
.
state
.
secondaryHue
,
primaryShade
:
this
.
state
.
primaryShade
,
secondaryShade
:
this
.
state
.
secondaryShade
,
};
if
(
saveTheme
)
{
newUserData
.
config
.
theme
=
this
.
getThemeFromProps
();
}
if
(
saveColorPicker
)
{
newUserData
.
config
.
colorPicker
=
{
primaryHue
:
this
.
state
.
primaryHue
,
secondaryHue
:
this
.
state
.
secondaryHue
,
primaryShade
:
this
.
state
.
primaryShade
,
secondaryShade
:
this
.
state
.
secondaryShade
,
};
}
this
.
props
.
saveToServer
(
newUserData
);
}
...
...
@@ -340,11 +355,9 @@ const mapDispatchToProps = (dispatch) => {
saveTheme
:
(
theme
)
=>
dispatch
(
saveAppTheme
(
theme
)),
saveColorPicker
:
(
partialState
)
=>
dispatch
(
saveAppColorPicker
(
partialState
)),
saveToServer
:
(
data
)
=>
dispatch
(
userDataElSaveData
(
data
)),
fetchUserDataSingle
:
(
id
)
=>
dispatch
(
userDataElFetchData
(
id
)),
fetchData
:
{
userDataEl
:
()
=>
dispatch
(
userDataElFetchData
(
""
)),
},
createUserData
:
()
=>
dispatch
(
userDataElSaveData
(
Object
()))
};
};
export
default
connect
(
mapStateToProps
,
mapDispatchToProps
)(
withStyles
(
styles
,
{
withTheme
:
true
})(
ColorTool
));
frontend/src/components/university/modules/UniversitySemestersDates.js
View file @
7768f71e
import
React
from
'
react
'
;
import
PropTypes
from
'
prop-types
'
;
import
{
withStyles
}
from
'
@material-ui/core/styles
'
;
import
{
compose
}
from
'
recompose
'
;
import
{
connect
}
from
"
react-redux
"
;
import
Table
from
'
@material-ui/core/Table
'
;
import
TableBody
from
'
@material-ui/core/TableBody
'
;
...
...
@@ -15,12 +17,18 @@ import Typography from '@material-ui/core/Typography';
import
CloudQueueIcon
from
'
@material-ui/icons/CloudQueue
'
;
import
LocalFloristIcon
from
'
@material-ui/icons/LocalFlorist
'
;
import
MyComponent
from
'
../../MyComponent
'
;
import
TextLink
from
'
../../other/TextLink
'
;
import
GenericModule
from
'
./GenericModule
'
;
import
Grid
from
'
@material-ui/core/Grid
'
;
import
Divider
from
'
@material-ui/core/Divider
'
;
import
MyComponent
from
'
../../MyComponent
'
;
import
{
universitiesSemestersDatesElFetchData
,
}
from
'
../../../generated/actions
'
;
const
styles
=
theme
=>
({
root
:
{
...
...
@@ -39,11 +47,39 @@ const styles = theme => ({
}
});
const
comment
=
"
**Attention certaines activités commencent avant cette période**
"
;
function
convertDate
(
date
)
{
if
(
date
)
{
const
d
=
new
Date
(
date
);
let
dd
=
d
.
getDate
();
let
mm
=
d
.
getMonth
()
+
1
;
dd
=
dd
<
10
?
'
0
'
+
dd
:
dd
;
mm
=
mm
<
10
?
'
0
'
+
mm
:
mm
;
const
yyyy
=
d
.
getFullYear
();
return
dd
+
'
/
'
+
mm
+
'
/
'
+
yyyy
;
}
else
{
return
"
Non connue.
"
}
}
class
UniversitySemestersDates
extends
MyComponent
{
idToUse
=
"
univId
"
;
customErrorHandlers
=
{
universitiesSemestersDatesEl
:
(
e
)
=>
{
console
.
log
(
e
);
return
true
;
}
}
myRender
()
{
const
{
classes
}
=
this
.
props
;
console
.
log
(
"
props
"
,
this
.
props
)
const
semestersDates
=
this
.
getFetchedData
(
'
universitiesSemestersDatesEl
'
);
let
{
autumn_begin
,
autumn_end
,
spring_begin
,
spring_end
,
comment
}
=
semestersDates
;
autumn_begin
=
convertDate
(
autumn_begin
);
autumn_end
=
convertDate
(
autumn_end
);
spring_begin
=
convertDate
(
spring_begin
);
spring_end
=
convertDate
(
spring_end
);
class
UniversitySemestersDates
extends
React
.
Component
{
render
()
{
const
{
classes
,
theme
}
=
this
.
props
;
return
(
<
GenericModule
title
=
{
"
Date des semestres
"
}
usefulLinks
=
{[{
description
:
"
Site de l'EPFL
"
,
url
:
"
https://epfl.ch
"
}]}
>
<
div
className
=
{
classes
.
root
}
>
...
...
@@ -64,8 +100,8 @@ class UniversitySemestersDates extends React.Component {
<
div
>
Automne
<
/div
>
<
/div
>
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
12
/
03
/
2018
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
12
/
03
/
2018
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
{
autumn_begin
}
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
{
autumn_end
}
<
/TableCell
>
<
/TableRow
>
<
TableRow
key
=
{
2
}
>
...
...
@@ -75,8 +111,8 @@ class UniversitySemestersDates extends React.Component {
<
div
>
Printemps
<
/div
>
<
/div
>
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
12
/
03
/
2018
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
12
/
03
/
2018
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
{
spring_begin
}
<
/TableCell
>
<
TableCell
className
=
{
classes
.
tableCell
}
component
=
"
td
"
>
{
spring_end
}
<
/TableCell
>
<
/TableRow
>
<
/TableBody
>
...
...
@@ -88,4 +124,30 @@ class UniversitySemestersDates extends React.Component {
}
}
export
default
withStyles
(
styles
,
{
withTheme
:
true
})(
UniversitySemestersDates
);
UniversitySemestersDates
.
propTypes
=
{
classes
:
PropTypes
.
object
.
isRequired
,
theme
:
PropTypes
.
object
.
isRequired
,
univId
:
PropTypes
.
string
.
isRequired
};
const
mapStateToProps
=
(
state
)
=>
{
return
{
universitiesSemestersDatesEl
:
state
.
universitiesSemestersDatesEl
,
};
};
const
mapDispatchToProps
=
(
dispatch
)
=>
{
return
{
fetchData
:
{
universitiesSemestersDatesEl
:
(
univId
)
=>
dispatch
(
universitiesSemestersDatesElFetchData
(
univId
)),
}
};
};
export
default
compose
(
withStyles
(
styles
,
{
withTheme
:
true
}),
connect
(
mapStateToProps
,
mapDispatchToProps
)
)(
UniversitySemestersDates
);
\ No newline at end of file
frontend/src/components/university/tabs/GeneralInfoTab.js
View file @
7768f71e
...
...
@@ -7,8 +7,6 @@ import { compose } from 'recompose';
import
GenericModule
from
'
../modules/GenericModule
'
;
import
Grid
from
'
@material-ui/core/Grid
'
;
import
Typography
from
'
@material-ui/core/Typography
'
;
import
Lorem
from
'
react-lorem-component
'
;
import
UniversityGeneral
from
'
../modules/UniversityGeneral
'
;
import
UniversitySemestersDates
from
'
../modules/UniversitySemestersDates
'
;
...
...
@@ -28,7 +26,9 @@ const styles = theme => ({
},
});
class
GeneralInfo
extends
MyComponent
{
class
GeneralInfoTab
extends
MyComponent
{
myRender
()
{
const
{
classes
,
theme
}
=
this
.
props
;
// Resizing with the grid was causing weird gaps so we rerender depending on the width
...
...
@@ -39,17 +39,17 @@ class GeneralInfo extends MyComponent {
<
div
style
=
{{
flexGrow
:
8
,
paddingRight
:
2
*
theme
.
spacing
.
unit
}}
>
<
Grid
container
direction
=
'
column
'
>
<
Grid
item
xs
style
=
{{
paddingBottom
:
2
*
theme
.
spacing
.
unit
}}
>
<
UniversityGeneral
/>
<
UniversityGeneral
univId
=
{
this
.
props
.
univId
}
/
>
<
/Grid
>
<
Grid
item
xs
>
<
UniversityDri
/>
<
UniversityDri
univId
=
{
this
.
props
.
univId
}
/
>
<
/Grid
>
<
/Grid
>
<
/div
>
<
div
style
=
{{
flexGrow
:
6
}}
>
<
Grid
container
direction
=
'
column
'
>
<
Grid
item
xs
style
=
{{
paddingBottom
:
2
*
theme
.
spacing
.
unit
}}
>
<
UniversitySemestersDates
/>
<
UniversitySemestersDates
univId
=
{
this
.
props
.
univId
}
/
>
<
/Grid
>
<
Grid
item
xs
>
<
GenericModule
title
=
{
"
Offres de départs
"
}
automaticData
=
{
true
}
/
>
...
...
@@ -66,13 +66,13 @@ class GeneralInfo extends MyComponent {
<
Grid
container
spacing
=
{
16
}
>
<
Grid
item
xs
=
{
12
}
>
<
UniversityGeneral
/>
<
UniversityGeneral
univId
=
{
this
.
props
.
univId
}
/
>
<
/Grid
>
<
Grid
item
xs
=
{
12
}
>
<
UniversityDri
/>
<
UniversityDri
univId
=
{
this
.
props
.
univId
}
/
>
<
/Grid
>
<
Grid
item
xs
=
{
12
}
>
<
UniversitySemestersDates
/>
<
UniversitySemestersDates
univId
=
{
this
.
props
.
univId
}
/
>
<
/Grid
>
<
Grid
item
xs
=
{
12
}
>
<
GenericModule
title
=
{
"
Offres de départs
"
}
automaticData
=
{
true
}
/
>
...
...
@@ -87,12 +87,14 @@ class GeneralInfo extends MyComponent {
}
// GeneralInfo.propTypes = {
// classes: PropTypes.object.isRequired,
// univId: PropTypes.string.isRequired,
// };
GeneralInfoTab
.
propTypes
=
{
classes
:
PropTypes
.
object
.
isRequired
,
theme
:
PropTypes
.
object
.
isRequired
,
univId
:
PropTypes
.
string
.
isRequired
};
export
default
compose
(
withWidth
({
noSSR
:
true
}),
withStyles
(
styles
,
{
withTheme
:
true
})
)(
GeneralInfo
);
\ No newline at end of file
withStyles
(
styles
,
{
withTheme
:
true
}),
)(
GeneralInfoTab
);
\ No newline at end of file
frontend/src/reducers/index.js
View file @
7768f71e
...
...
@@ -8,7 +8,9 @@ import {
universitiesElReducers
,
currenciesReducers
,
citiesReducers
,
userDataElReducers
userDataElReducers
,
universitiesInfoElReducers
,
universitiesSemestersDatesElReducers
}
from
'
../generated/combinedReducers
'
;
import
{
saveMainMapPosition
}
from
'
./map
'
;
...
...
@@ -32,6 +34,8 @@ const rootReducer = combineReducers({
cities
:
citiesReducers
,
universities
:
universitiesReducers
,
universitiesEl
:
universitiesElReducers
,
universitiesInfoEl
:
universitiesInfoElReducers
,
universitiesSemestersDatesEl
:
universitiesSemestersDatesElReducers
,
currencies
:
currenciesReducers
,
mainCampuses
:
mainCampusesReducers
,
userDataEl
:
userDataElReducers
,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment