Commit ae856352 authored by Florent Chehab's avatar Florent Chehab

Tweaks and university DRI display and edit ok

parent 35b8ea0f
......@@ -36,7 +36,7 @@ function _FetchData(pk, api_end_point, _IsLoading, _FetchDataSuccess, _Invalidat
throw "pk shouldn't be empty when requesting a specific element";
}
if (pk != ""){
api_end_point += pk;
api_end_point += pk + '/';
}
return (dispatch) => {
dispatch(_IsLoading(true));
......@@ -71,11 +71,16 @@ function _ElSaveData(data, api_end_point, _ElIsSaving, _ElFetchDataSuccess, _ElS
method = "PUT";
pk = data.id + '/';
}
let __apiAttr = '';
if ('__apiAttr' in data && data.__apiAttr != '' ){
__apiAttr = data.__apiAttr + '/';
}
let errorStatusText = '';
dispatch(_ElIsSaving(true));
let token = Cookies.get('csrftoken');
let f = fetch(api_end_point+pk, {
let f = fetch(api_end_point+__apiAttr+pk, {
method: method,
credentials: 'same-origin',
headers: {
......
......@@ -3,7 +3,11 @@ import Loading from './other/Loading';
class MyComponent extends Component {
customErrorHandlers = {}
idToUse = null;
// __apiAttr should be an object
// mapping the prop that needs to fetched with extra api attributes
// mapping should be : props_key => other_props_that contains the attribute to use
__apiAttr = null;
ignoreInvalidation = false;
getFetchedData(prop) {
return this.props[prop].fetched.data;
......@@ -92,12 +96,12 @@ class MyComponent extends Component {
for (let prop_key in props) {
let prop = props[prop_key];
if (prop === Object(prop) && 'fetched' in prop) {
if ((!prop.fetched.fetchedAt) || prop.invalidated) {
if ((!prop.fetched.fetchedAt) || (!this.ignoreInvalidation && prop.invalidated)) {
propsLoaded = false;
if (!dontFetch) {
if (!prop.isLoading) {
if (this.idToUse) {
props.fetchData[prop_key](this.props[this.idToUse]);
if (this.__apiAttr && this.__apiAttr[prop_key]) {
props.fetchData[prop_key](this.props[this.__apiAttr[prop_key]]);
} else {
props.fetchData[prop_key]();
}
......
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import compose from 'recompose/compose';
import { connect } from "react-redux";
import Editor from '../shared/Editor';
import editorStyle from '../shared/editorStyle';
import MultiSelectField from '../shared/fields/MultiSelectField';
import __map from 'lodash/map';
import getMapStateToPropsForEditor from '../shared/editorFunctions/getMapStateToPropsForEditor';
import getMapDispatchToPropsForEditor from '../shared/editorFunctions/getMapDispatchToPropsForEditor';
import {
universityDriElSaveData,
universityDriElSavingHasError
} from '../../../generated/actions';
const styles = theme => ({
...editorStyle(theme)
});
class UniversityDriEditor extends Editor {
renderEditor() {
const { modelData } = this.props;
const { outsideData } = this.props;
const universities = __map(outsideData.universities,
(univ) => { return { label: univ.name, value: univ.id, disabled: false } }
)
return (
<div>
{this.renderTitleField()}
{this.renderImportanceLevelField()}
<MultiSelectField label={"Universités concernées"}
required={true}
value={modelData.universities}
options={universities}
formManager={this}
fieldMapping={'universities'}
/>
{this.renderCommentField()}
{this.renderUsefulLinksField()}
</div>
)
}
}
UniversityDriEditor.propTypes = {
modelData: PropTypes.object.isRequired,
};
export default compose(
withStyles(styles, { withTheme: true }),
connect(
getMapStateToPropsForEditor('universityDriEl'),
getMapDispatchToPropsForEditor(universityDriElSaveData, universityDriElSavingHasError)
)
)(UniversityDriEditor);
\ No newline at end of file
......@@ -79,16 +79,8 @@ class UniversitySemestersDatesEditor extends Editor {
formManager={this}
fieldMapping={'autumn_end'}
/>
<MarkdownField label={"Éventuel commentaire associé à ces informations"} maxLength={100}
value={modelData.comment}
formManager={this}
fieldMapping={'comment'}
/>
<UsefulLinksField label={"Lien(s) utile(s) (ex : vers ces informations)"}
value={modelData.useful_links}
formManager={this}
fieldMapping={'useful_links'}
/>
{this.renderCommentField()}
{this.renderUsefulLinksField()}
</div>
)
}
......
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import Paper from '@material-ui/core/Paper';
import GenericModule from '../shared/GenericModule';
import compose from 'recompose/compose';
import { connect } from "react-redux";
import __pick from 'lodash/pick';
import Markdown from '../../shared/Markdown';
import MyComponent from '../../MyComponent';
import GenericModule from '../shared/GenericModule';
import GenericGroupModule from '../shared/GenericGroupModule';
import UniversityDriEditor from '../editors/UniversityDriEditor';
const styles = theme => ({
import {
universitiesFetchData,
universityDriFetchData,
universityDriInvalidated,
} from '../../../generated/actions';
const styles = theme => ({
});
function renderCore(rawModelData, classes, outsideData) {
const univDri = rawModelData;
const { comment } = univDri;
return (
<Markdown source={comment} />
)
}
function parseRawModelData(rawModelData) {
// reverse serialization
const univInfos = rawModelData;
const modelData = __pick(univInfos,
[
"id",
"title",
"importance_level",
"universities",
"comment",
"useful_links",
// "obj_moderation_level",
]);
return modelData;
}
class UniversityDri extends MyComponent {
ignoreInvalidation = true;
componentWillUnmount() {
this.props.invalidateData();
}
myComponentDidUpdate() {
if (this.props.universityDri.invalidated && !this.props.universityDri.isLoading) {
this.props.fetchData.universityDri(this.props.univId);
}
}
myRender() {
const univDriItems = this.getFetchedData('universityDri');
const universities = this.getFetchedData('universities')
const { classes } = this.props;
const outsideData = {
universities
}
class UniversityDri extends React.Component {
render() {
const { classes, theme } = this.props;
return (
<GenericGroupModule groupTitle={"Informations émanant de la DRI"}>
<GenericModule title={"DRI"} importanceLevel={'IMPORTANT'} />
{
univDriItems.map((rawModelData) => (
<GenericModule
visible={this.props.visible}
buildTitle={(modelData) => modelData.title}
rawModelData={rawModelData}
parseRawModelData={parseRawModelData}
editor={UniversityDriEditor}
renderCore={renderCore}
coreClasses={classes}
outsideData={outsideData}
moduleInGroupInfos={{ isInGroup: true, invalidateGroup: () => this.props.invalidateData() }}
__apiAttr={this.props.univId}
/>
))
}
</GenericGroupModule >
)
}
__apiAttr = { universityDri: "univId" };
}
export default withStyles(styles, { withTheme: true })(UniversityDri);
UniversityDri.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
univId: PropTypes.string.isRequired
};
const mapStateToProps = (state) => {
return {
universityDri: state.universityDri,
universities: state.universities,
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: {
universityDri: (univId) => dispatch(universityDriFetchData(univId)),
universities: () => dispatch(universitiesFetchData()),
},
invalidateData: () => dispatch(universityDriInvalidated(true))
};
};
export default compose(
withStyles(styles, { withTheme: true }),
connect(mapStateToProps, mapDispatchToProps)
)(UniversityDri);
\ No newline at end of file
......@@ -88,8 +88,6 @@ function parseRawModelData(rawModelData) {
class UniversityGeneral extends MyComponent {
idToUse = "univId";
componentWillUnmount() {
this.props.invalidateData();
}
......@@ -120,6 +118,8 @@ class UniversityGeneral extends MyComponent {
/>
)
}
__apiAttr = { universitiesEl: "univId" };
}
UniversityGeneral.propTypes = {
......
......@@ -127,7 +127,6 @@ function parseRawModelData(rawModelData) {
class UniversitySemestersDates extends MyComponent {
idToUse = "univId";
componentWillUnmount() {
this.props.invalidateData();
......@@ -147,6 +146,8 @@ class UniversitySemestersDates extends MyComponent {
/>
)
}
__apiAttr = { universitiesSemestersDatesEl: "univId" };
}
......
......@@ -15,6 +15,9 @@ import Alert from './Alert';
import Notification from './Notification';
import getObjModerationLevel from '../../../utils/getObjModerationLevels';
import SelectField from './fields/SelectField';
import UsefulLinksField from './fields/UsefulLinksField';
import MarkdownField from './fields/MarkdownField';
import TextField from './fields/TextField';
function Transition(props) {
return <Slide direction="up" {...props} />;
......@@ -96,7 +99,8 @@ class Editor extends MyComponent {
duration: null
}
})
this.props.saveData(data);
this.props.saveData(Object.assign({ __apiAttr: this.props.__apiAttr }, data));
}
handleSaveEditor() {
......@@ -183,7 +187,7 @@ class Editor extends MyComponent {
preventClickAway: false
}
})
this.props.handleCloseEditor();
this.props.handleCloseEditor(true);
}
};
......@@ -232,7 +236,7 @@ class Editor extends MyComponent {
}
renderObjModerationLevelField() {
const { modelData } = this.props;
const { obj_moderation_level } = this.props.modelData;
const possibleObjModeration = getObjModerationLevel(this.getFetchedData('userData').owner_level, true);
if (possibleObjModeration.length > 1) {
......@@ -241,7 +245,7 @@ class Editor extends MyComponent {
<Typography variant='caption'>Niveau de modération souhaité (en plus TODO </Typography>
<SelectField label={"Niveau de modération pour ce module"}
required={true}
value={modelData.obj_moderation_level}
value={obj_moderation_level}
fieldMapping={"obj_moderation_level"}
options={possibleObjModeration}
formManager={this}
......@@ -255,6 +259,66 @@ class Editor extends MyComponent {
}
}
renderImportanceLevelField() {
const { importance_level } = this.props.modelData;
//TODO change below use JSON
const options = [
{ 'label': 'Normal', 'value': '-' },
{ 'label': 'Important', 'value': '+' },
{ 'label': 'Très important', 'value': '++' },
]
return (
<div>
<Typography variant='caption'>Qualification de l'importance de l'information présentée</Typography>
<SelectField label={"Niveau d'importance"}
required={true}
value={importance_level}
fieldMapping={"importance_level"}
options={options}
formManager={this}
/>
</div>
)
}
renderUsefulLinksField() {
const { useful_links } = this.props.modelData;
return (
<UsefulLinksField label={"Lien(s) utile(s) (ex : vers ces informations)"}
value={useful_links}
formManager={this}
fieldMapping={'useful_links'}
/>
)
}
renderCommentField() {
const { comment } = this.props.modelData;
return (
<MarkdownField label={"Commentaire associé à ces informations"}
maxLength={100}
value={comment}
formManager={this}
fieldMapping={'comment'}
/>
)
}
renderTitleField() {
const { title } = this.props.modelData;
return (
<TextField label={"Titre"}
required={true}
value={title}
maxLength={150}
formManager={this}
fieldMapping={'title'}
/>
)
}
myRender() {
const { classes } = this.props;
return (
......@@ -300,12 +364,17 @@ Editor.propTypes = {
savingHasError: PropTypes.object.isRequired,
saveData: PropTypes.func.isRequired,
lastUpdateTime: PropTypes.string,
forceSave: PropTypes.bool.isRequired
forceSave: PropTypes.bool.isRequired,
outsideData: PropTypes.object,
saveShouldInvalidate: PropTypes.bool.isRequired,
__apiAttr: PropTypes.oneOf([PropTypes.number, PropTypes.string]),
};
Editor.defaultProps = {
open: false,
forceSave: false,
saveShouldInvalidate: false,
__apiAttr: '',
handleCloseEditor: () => console.log("Dev forgot something...")
};
......
......@@ -112,8 +112,11 @@ class GenericModule extends MyComponent {
};
handleCloseEditor = () => {
handleCloseEditor = (somethingWasSaved = false) => {
this.setState({ editorOpen: false, dataToSave: null });
if (somethingWasSaved && this.props.moduleInGroupInfos.isInGroup) {
this.props.moduleInGroupInfos.invalidateGroup();
}
};
handleCloseAlert = () => {
......@@ -209,9 +212,11 @@ class GenericModule extends MyComponent {
open={this.state.editorOpen}
handleCloseEditor={this.handleCloseEditor}
modelData={this.props.parseRawModelData(this.state.rawModelDataForEditor)}
outsideData={this.props.outsideData}
userData={this.props.userDataEl}
forceSave={this.state.forceSave}
dataToSave={this.state.dataToSave}
__apiAttr={this.props.__apiAttr}
/>
<History
factory={this}
......@@ -239,6 +244,8 @@ class GenericModule extends MyComponent {
GenericModule.defaultProps = {
buildTitle: () => null,
moduleInGroupInfos: { isInGroup: false, invalidateGroup: () => null },
__apiAttr: '',
};
GenericModule.propTypes = {
......@@ -250,6 +257,8 @@ GenericModule.propTypes = {
parseRawModelData: PropTypes.func.isRequired,
coreClasses: PropTypes.object.isRequired,
outsideData: PropTypes.object,
__apiAttr: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
moduleInGroupInfos: PropTypes.shape({ isInGroup: PropTypes.bool.isRequired, invalidateGroup: PropTypes.func }).isRequired,
};
......
......@@ -42,7 +42,7 @@ class GeneralInfoTab extends MyComponent {
<UniversityGeneral visible={this.props.visible} univId={this.props.univId} />
</Grid>
<Grid item xs>
{/* <UniversityDri visible={this.props.visible} univId={this.props.univId} /> */}
<UniversityDri visible={this.props.visible} univId={this.props.univId} />
</Grid>
</Grid>
</div>
......@@ -69,7 +69,7 @@ class GeneralInfoTab extends MyComponent {
<UniversityGeneral visible={this.props.visible} univId={this.props.univId} />
</Grid>
<Grid item xs={12}>
{/* <UniversityDri visible={this.props.visible} univId={this.props.univId} /> */}
<UniversityDri visible={this.props.visible} univId={this.props.univId} />
</Grid>
<Grid item xs={12}>
<UniversitySemestersDates visible={this.props.visible} univId={this.props.univId} />
......
......@@ -10,9 +10,11 @@ import {
citiesReducers,
userDataElReducers,
universitiesInfoElReducers,
universityDriReducers,
universityDriElReducers,
universitiesSemestersDatesElReducers,
serverModerationStatusReducers,
versionsReducers
versionsReducers,
} from '../generated/combinedReducers';
import { saveMainMapPosition } from './map';
......@@ -39,6 +41,8 @@ const rootReducer = combineReducers({
universitiesEl: universitiesElReducers,
universitiesInfoEl: universitiesInfoElReducers,
universitiesSemestersDatesEl: universitiesSemestersDatesElReducers,
universityDri: universityDriReducers,
universityDriEl: universityDriElReducers,
currencies: currenciesReducers,
mainCampuses: mainCampusesReducers,
userDataEl: userDataElReducers,
......
......@@ -14,7 +14,7 @@ export default function isModerationRequired(
objModerationLevel,
userLevel) {
const { modelModerationLevel } = modelConfig;
const modelModerationLevel = modelConfig.moderation_level;
const key = 'enforce_moderation_user_level';
if (key in modelConfig && userLevel < modelConfig[key]) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment