Commit 1946dbe9 authored by Florent Chehab's avatar Florent Chehab
Browse files

All editors are back and started redisign of fields

parent 56e9236a
...@@ -40,6 +40,6 @@ module.exports = { ...@@ -40,6 +40,6 @@ module.exports = {
], ],
"react/no-unescaped-entities": "off", // that one doesn't improve code readability "react/no-unescaped-entities": "off", // that one doesn't improve code readability
"react/prop-types": "error", "react/prop-types": "error",
"react/no-deprecated": "warn" "react/no-deprecated": "error"
} }
}; };
...@@ -5,19 +5,21 @@ import compose from "recompose/compose"; ...@@ -5,19 +5,21 @@ import compose from "recompose/compose";
import { connect } from "react-redux"; import { connect } from "react-redux";
import Editor from "../shared/Editor"; import Editor from "../shared/Editor";
import Form from "../shared/Form";
import editorStyle from "../shared/editorStyle"; import editorStyle from "../shared/editorStyle";
import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor"; import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor";
import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor"; import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor";
import { withSnackbar } from "notistack";
const styles = theme => ({ const styles = theme => ({
...editorStyle(theme) ...editorStyle(theme)
}); });
class CountryDriEditor extends Editor {
renderEditor() { class CountryDriForm extends Form {
render() {
return ( return (
<div> <div>
{this.renderTitleField()} {this.renderTitleField()}
...@@ -30,12 +32,24 @@ class CountryDriEditor extends Editor { ...@@ -30,12 +32,24 @@ class CountryDriEditor extends Editor {
} }
} }
class CountryDriEditor extends Editor {
renderForm() {
return <CountryDriForm
modelData={this.props.modelData}
outsideData={this.props.outsideData}
ref={this.formRef}
/>;
}
}
CountryDriEditor.propTypes = { CountryDriEditor.propTypes = {
modelData: PropTypes.object.isRequired, modelData: PropTypes.object.isRequired,
}; };
export default compose( export default compose(
withSnackbar,
withStyles(styles, { withTheme: true }), withStyles(styles, { withTheme: true }),
connect( connect(
getMapStateToPropsForEditor("countryDri"), getMapStateToPropsForEditor("countryDri"),
......
import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles"; import withStyles from "@material-ui/core/styles/withStyles";
import compose from "recompose/compose"; import compose from "recompose/compose";
import { connect } from "react-redux"; import { connect } from "react-redux";
import ScholarshipsEditor from "../shared/ScholarshipsEditor"; import Editor from "../shared/Editor";
import ScholarshipForm from "../shared/ScholarshipForm";
import editorStyle from "../shared/editorStyle"; import editorStyle from "../shared/editorStyle";
import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor"; import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor";
import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor"; import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor";
import { withSnackbar } from "notistack";
const styles = theme => ({ const styles = theme => ({
...editorStyle(theme) ...editorStyle(theme)
}); });
class CountryScholarshipsEditor extends ScholarshipsEditor {
class CountryScholarshipForm extends ScholarshipForm {
renderLinkedField() { renderLinkedField() {
return this.renderCountriesField(); return this.renderCountriesField();
} }
} }
CountryScholarshipsEditor.propTypes = { class CountryScholarshipEditor extends Editor {
renderForm() {
return (
<CountryScholarshipForm
modelData={this.props.modelData}
outsideData={this.props.outsideData}
ref={this.formRef}
/>
);
}
}
CountryScholarshipEditor.propTypes = {
modelData: PropTypes.object.isRequired, modelData: PropTypes.object.isRequired,
outsideData: PropTypes.object.isRequired,
}; };
export default compose( export default compose(
withSnackbar,
withStyles(styles, { withTheme: true }), withStyles(styles, { withTheme: true }),
connect( connect(
getMapStateToPropsForEditor("countryScholarships"), getMapStateToPropsForEditor("countryScholarships"),
getMapDispatchToPropsForEditor("countryScholarships") getMapDispatchToPropsForEditor("countryScholarships")
) )
)(CountryScholarshipsEditor); )(CountryScholarshipEditor);
...@@ -43,6 +43,7 @@ class UniversityDriEditor extends Editor { ...@@ -43,6 +43,7 @@ class UniversityDriEditor extends Editor {
UniversityDriEditor.propTypes = { UniversityDriEditor.propTypes = {
modelData: PropTypes.object.isRequired, modelData: PropTypes.object.isRequired,
outsideData: PropTypes.object.isRequired,
}; };
......
import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles"; import withStyles from "@material-ui/core/styles/withStyles";
import compose from "recompose/compose"; import compose from "recompose/compose";
import { connect } from "react-redux"; import { connect } from "react-redux";
import ScholarshipsEditor from "../shared/ScholarshipsEditor"; import Editor from "../shared/Editor";
import ScholarshipForm from "../shared/ScholarshipForm";
import editorStyle from "../shared/editorStyle"; import editorStyle from "../shared/editorStyle";
import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor"; import getMapStateToPropsForEditor from "../shared/editorFunctions/getMapStateToPropsForEditor";
import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor"; import getMapDispatchToPropsForEditor from "../shared/editorFunctions/getMapDispatchToPropsForEditor";
import { withSnackbar } from "notistack";
const styles = theme => ({ const styles = theme => ({
...editorStyle(theme) ...editorStyle(theme)
}); });
class UniversityScholarshipsEditor extends ScholarshipsEditor {
class UniversityScholarshipForm extends ScholarshipForm {
renderLinkedField() { renderLinkedField() {
return this.renderUniversitiesField(); return this.renderUniversitiesField();
} }
} }
UniversityScholarshipsEditor.propTypes = { class UniversityScholarshipEditor extends Editor {
renderForm() {
return (
<UniversityScholarshipForm
modelData={this.props.modelData}
outsideData={this.props.outsideData}
ref={this.formRef}
/>
);
}
}
UniversityScholarshipEditor.propTypes = {
modelData: PropTypes.object.isRequired, modelData: PropTypes.object.isRequired,
outsideData: PropTypes.object.isRequired,
}; };
export default compose( export default compose(
withSnackbar,
withStyles(styles, { withTheme: true }), withStyles(styles, { withTheme: true }),
connect( connect(
getMapStateToPropsForEditor("universityScholarships"), getMapStateToPropsForEditor("universityScholarships"),
getMapDispatchToPropsForEditor("universityScholarships") getMapDispatchToPropsForEditor("universityScholarships")
) )
)(UniversityScholarshipsEditor); )(UniversityScholarshipEditor);
...@@ -23,7 +23,7 @@ const styles = theme => ({ ...@@ -23,7 +23,7 @@ const styles = theme => ({
class UniversitySemestersDatesForm extends Form { class UniversitySemestersDatesForm extends Form {
hasError() { hasFormLevelErrors() {
let messages = Array(); let messages = Array();
const formData = this.getDataFromFields(); const formData = this.getDataFromFields();
const { autumn_begin, autumn_end, spring_begin, spring_end } = formData; const { autumn_begin, autumn_end, spring_begin, spring_end } = formData;
...@@ -44,10 +44,7 @@ class UniversitySemestersDatesForm extends Form { ...@@ -44,10 +44,7 @@ class UniversitySemestersDatesForm extends Form {
messages.push("Le début du semestre de printemps doit être antérieur à sa fin..."); messages.push("Le début du semestre de printemps doit être antérieur à sa fin...");
} }
const formLevelErrors = this.buildError(messages), return this.buildError(messages);
fieldLevelErrors = super.hasError();
return this.combineErrors([fieldLevelErrors, formLevelErrors]);
} }
render() { render() {
......
...@@ -11,7 +11,7 @@ import ModuleWrapper from "../shared/ModuleWrapper"; ...@@ -11,7 +11,7 @@ import ModuleWrapper from "../shared/ModuleWrapper";
import ModuleGroupWrapper from "../shared/ModuleGroupWrapper"; import ModuleGroupWrapper from "../shared/ModuleGroupWrapper";
import Scholarship from "../shared/Scholarship"; import Scholarship from "../shared/Scholarship";
import CountryScholarshipsEditor from "../editors/CountryScholarshipsEditor"; import CountryScholarshipEditor from "../editors/CountryScholarshipEditor";
import getActions from "../../../api/getActions"; import getActions from "../../../api/getActions";
...@@ -78,7 +78,7 @@ class CountryScholarships extends Module { ...@@ -78,7 +78,7 @@ class CountryScholarships extends Module {
<ModuleGroupWrapper <ModuleGroupWrapper
groupTitle={`Bourses liées au pays (${this.props.country.name})`} groupTitle={`Bourses liées au pays (${this.props.country.name})`}
endPoint={"countryScholarship"} endPoint={"countryScholarship"}
editor={CountryScholarshipsEditor} editor={CountryScholarshipEditor}
invalidateGroup={this.props.invalidateData} invalidateGroup={this.props.invalidateData}
propsForEditor={{ propsForEditor={{
modelData: { countries: [this.props.countryId], importance_level: "-", currency: "EUR", obj_moderation_level: 0 }, modelData: { countries: [this.props.countryId], importance_level: "-", currency: "EUR", obj_moderation_level: 0 },
...@@ -94,7 +94,7 @@ class CountryScholarships extends Module { ...@@ -94,7 +94,7 @@ class CountryScholarships extends Module {
buildTitle={(modelData) => modelData.title} buildTitle={(modelData) => modelData.title}
rawModelData={rawModelData} rawModelData={rawModelData}
parseRawModelData={parseRawModelData} parseRawModelData={parseRawModelData}
editor={CountryScholarshipsEditor} editor={CountryScholarshipEditor}
renderCore={renderCore} renderCore={renderCore}
coreClasses={classes} coreClasses={classes}
outsideData={outsideData} outsideData={outsideData}
......
...@@ -11,7 +11,7 @@ import ModuleWrapper from "../shared/ModuleWrapper"; ...@@ -11,7 +11,7 @@ import ModuleWrapper from "../shared/ModuleWrapper";
import ModuleGroupWrapper from "../shared/ModuleGroupWrapper"; import ModuleGroupWrapper from "../shared/ModuleGroupWrapper";
import Scholarship from "../shared/Scholarship"; import Scholarship from "../shared/Scholarship";
import UniversityScholarshipsEditor from "../editors/UniversityScholarshipsEditor"; import UniversityScholarshipEditor from "../editors/UniversityScholarshipEditor";
import getActions from "../../../api/getActions"; import getActions from "../../../api/getActions";
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
...@@ -76,7 +76,7 @@ class UniversityScholarships extends Module { ...@@ -76,7 +76,7 @@ class UniversityScholarships extends Module {
<ModuleGroupWrapper <ModuleGroupWrapper
groupTitle={"Bourses liées à l'université"} groupTitle={"Bourses liées à l'université"}
endPoint={"universityScholarship"} endPoint={"universityScholarship"}
editor={UniversityScholarshipsEditor} editor={UniversityScholarshipEditor}
invalidateGroup={this.props.invalidateData} invalidateGroup={this.props.invalidateData}
propsForEditor={{ propsForEditor={{
modelData: { universities: [this.props.univId], importance_level: "-", currency: "EUR", obj_moderation_level: 0 }, modelData: { universities: [this.props.univId], importance_level: "-", currency: "EUR", obj_moderation_level: 0 },
...@@ -92,7 +92,7 @@ class UniversityScholarships extends Module { ...@@ -92,7 +92,7 @@ class UniversityScholarships extends Module {
buildTitle={(modelData) => modelData.title} buildTitle={(modelData) => modelData.title}
rawModelData={rawModelData} rawModelData={rawModelData}
parseRawModelData={parseRawModelData} parseRawModelData={parseRawModelData}
editor={UniversityScholarshipsEditor} editor={UniversityScholarshipEditor}
renderCore={renderCore} renderCore={renderCore}
coreClasses={classes} coreClasses={classes}
outsideData={outsideData} outsideData={outsideData}
......
import React, { Component } from "react"; import { Component } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import areSameObjects from "../../../utils/areSameObjects"; import areSameObjects from "../../../utils/areSameObjects";
...@@ -108,21 +108,36 @@ class Form extends Component { ...@@ -108,21 +108,36 @@ class Form extends Component {
*/ */
fieldsHaveError() { fieldsHaveError() {
const messages = this.getFields() const messages = this.getFields()
.map(({ field }) => field.getError().messages) .map(({ field }) => field.hasError().messages)
.filter(messages => messages.length > 0); .filter(messages => messages.length > 0);
return this.buildError(messages); return this.buildError(messages);
} }
/** /**
* Function to know if the form has errors. * Function to know if the form has errors either at the field level
* Or when running checks that combine fields
* *
* It can be override in subclasses to handle errors at the form level * YOU SHOULDN'T OVERRIDE THIS
* (multiple fields checks)
* *
* @returns * @returns
* @memberof Form * @memberof Form
*/ */
hasError() { hasError() {
return this.combineErrors([
this.fieldsHaveError(),
this.hasFormLevelErrors()
]);
}
/**
* Function to check for errors in the form
*
* Can be override in sub classes
*
* @returns object built with this.buildError
* @memberof Form
*/
hasFormLevelErrors() {
return this.fieldsHaveError(); return this.fieldsHaveError();
} }
......
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import Editor from "./Editor"; import Form from "./Form";
const frequencyOptions = [ const frequencyOptions = [
{ value: "w", label: "Il s'agit du montant hebdomadaire" }, { value: "w", label: "Il s'agit du montant hebdomadaire" },
...@@ -11,18 +11,20 @@ const frequencyOptions = [ ...@@ -11,18 +11,20 @@ const frequencyOptions = [
{ value: "o", label: "Il s'agit d'un montant donné une seule fois" } { value: "o", label: "Il s'agit d'un montant donné une seule fois" }
]; ];
class ScholarshipEditor extends Editor { class ScholarshipForm extends Form {
formHasError() {
hasFormLevelErrors() {
let messages = Array(); let messages = Array();
const formData = this.getDataFromFields(); const formData = this.getDataFromFields();
const { amount_min, amount_max } = formData; const { amount_min, amount_max } = formData;
if (amount_min !== null && amount_max !== null && amount_max < amount_min) { if (amount_min !== null && amount_max !== null && amount_max < amount_min) {
messages.push("La logique voudrait que la borne supérieure de la bourse soit... supérieure à la borne inférieure."); messages.push("La logique voudrait que la borne supérieure de la bourse soit... supérieure à la borne inférieure.");
} }
return this.buildError(messages); return this.buildError(messages);
} }
renderEditor() { render() {
return ( return (
<div> <div>
{this.renderObjModerationLevelField()} {this.renderObjModerationLevelField()}
...@@ -49,6 +51,7 @@ class ScholarshipEditor extends Editor { ...@@ -49,6 +51,7 @@ class ScholarshipEditor extends Editor {
label: "Fréquence de la bourse", label: "Fréquence de la bourse",
options: frequencyOptions, options: frequencyOptions,
fieldMapping: "frequency", fieldMapping: "frequency",
required: true, //TODO remove
})} })}
{this.renderMarkdownField({ {this.renderMarkdownField({
label: "Autres avantages", label: "Autres avantages",
...@@ -63,8 +66,8 @@ class ScholarshipEditor extends Editor { ...@@ -63,8 +66,8 @@ class ScholarshipEditor extends Editor {
} }
} }
ScholarshipEditor.propTypes = { ScholarshipForm.propTypes = {
modelData: PropTypes.object.isRequired, modelData: PropTypes.object.isRequired,
}; };
export default ScholarshipEditor; export default ScholarshipForm;
...@@ -9,7 +9,6 @@ import format from "date-fns/format"; ...@@ -9,7 +9,6 @@ import format from "date-fns/format";
import KeyboardArrowLeftIcon from "@material-ui/icons/KeyboardArrowLeft"; import KeyboardArrowLeftIcon from "@material-ui/icons/KeyboardArrowLeft";
import KeyboardArrowRightIcon from "@material-ui/icons/KeyboardArrowRight"; import KeyboardArrowRightIcon from "@material-ui/icons/KeyboardArrowRight";
import FieldWrapper from "./FieldWrapper";
import dateToDateStr from "../../../../utils/dateToDateStr"; import dateToDateStr from "../../../../utils/dateToDateStr";
import Field from "./Field"; import Field from "./Field";
...@@ -33,7 +32,8 @@ class DateField extends Field { ...@@ -33,7 +32,8 @@ class DateField extends Field {
return dateToDateStr(this.state.value); return dateToDateStr(this.state.value);
} }
hasError(date) { hasError() {
const date = this.state.value;
let messages = Array(); let messages = Array();
if (this.props.required && !date) { if (this.props.required && !date) {
messages.push("Date requise !"); messages.push("Date requise !");
...@@ -47,27 +47,20 @@ class DateField extends Field { ...@@ -47,27 +47,20 @@ class DateField extends Field {
}); });
} }
render() { renderField() {
return ( return (
<FieldWrapper <MuiPickersUtilsProvider utils={LocalizedUtils} locale={frLocale}>
required={this.props.required} <DatePicker
hasError={this.state.error.status} clearable
errors={this.state.error.messages} format="d MMM yyyy"
label={this.props.label} value={this.state.value}
> onChange={this.handleDateChange}
<MuiPickersUtilsProvider utils={LocalizedUtils} locale={frLocale}> clearLabel="vider"
<DatePicker cancelLabel="annuler"
clearable leftArrowIcon={<KeyboardArrowLeftIcon />}
format="d MMM yyyy" rightArrowIcon={<KeyboardArrowRightIcon />}
value={this.state.value} />
onChange={this.handleDateChange}