Commit 1c435959 authored by Florent Chehab's avatar Florent Chehab
Browse files

Better than ever from poo

New fields
parent ee9a98b3
......@@ -13,7 +13,6 @@ import Slide from '@material-ui/core/Slide';
import MyComponent from '../../../MyComponent';
import Alert from './Alert';
import dateToDateStr from '../../../../utils/dateToDateStr';
import getObjModerationLevel from '../../../../utils/getObjModerationLevels';
import SelectField from './fields/SelectField';
......@@ -22,8 +21,15 @@ function Transition(props) {
}
class Editor extends MyComponent {
formData = {};
formError = {};
fields = Object();
addField(field, fieldMapping) {
this.fields[fieldMapping] = field;
}
removeField(fieldMapping) {
delete this.fields[fieldMapping];
}
state = {
alert: {
......@@ -32,6 +38,40 @@ class Editor extends MyComponent {
lastSave: this.props.lastSave,
}
formIsValid() {
// to override if you need to perform some checks at the form level
return true;
}
formFieldsHaveError() {
for (let fieldKey in this.fields) {
const field = this.fields[fieldKey];
if (field.getHasError()) {
return true;
}
}
return false;
}
getDataFromFields() {
let data = Object();
for (let fieldKey in this.fields) {
const field = this.fields[fieldKey];
data[fieldKey] = field.getValue();
}
return data;
}
handleSaveEditor() {
if (this.formIsValid()) {
const tmp = Object.assign({}, this.props.modelData, this.getDataFromFields())
this.props.saveData(tmp);
} else {
console.log("ici")
}
}
myComponentDidUpdate() {
const { savingHasError } = this.props;
if (savingHasError.status) {
......@@ -63,15 +103,6 @@ class Editor extends MyComponent {
})
}
setFormDataAndError(field, data, type = null) {
let correctData = data.data;
if (type == 'date') {
correctData = dateToDateStr(correctData);
}
this.formData[field] = correctData;
this.formError[field] = data.hasError;
}
renderEditor() {
return (<div>No editor set</div>)
}
......@@ -85,8 +116,9 @@ class Editor extends MyComponent {
<SelectField label={"Niveau de modération pour ce module"}
required={true}
value={modelData.obj_moderation_level}
fieldMapping={"obj_moderation_level"}
options={possibleObjModeration}
onChange={(data) => this.setFormDataAndError('obj_moderation_level', data)}
formManager={this}
/>
)
} else {
......@@ -136,6 +168,7 @@ Editor.propTypes = {
classes: PropTypes.object.isRequired,
clearSaveError: PropTypes.func.isRequired,
savingHasError: PropTypes.bool.isRequired,
saveData: PropTypes.func.isRequired,
};
Editor.defaultProps = {
......
......@@ -24,11 +24,7 @@ const styles = theme => ({
class UniversitySemestersDatesEditor extends Editor {
handleSaveEditor() {
const tmp = Object.assign({}, this.props.modelData, this.formData)
this.props.saveData(tmp);
}
renderEditor() {
const { modelData } = this.props;
......@@ -36,28 +32,34 @@ class UniversitySemestersDatesEditor extends Editor {
<div>
{this.renderObjModerationLevelField()}
<DateField label={"Date de début du semestre de printemps"}
selectedDate={modelData.spring_begin}
onChange={(data) => this.setFormDataAndError('spring_begin', data, 'date')}
value={modelData.spring_begin}
formManager={this}
fieldMapping={'spring_begin'}
/>
<DateField label={"Date de fin du semestre de printemps"}
selectedDate={modelData.spring_end}
onChange={(data) => this.setFormDataAndError('spring_end', data, 'date')}
value={modelData.spring_end}
formManager={this}
fieldMapping={'spring_end'}
/>
<DateField label={"Date de début du semestre d'automne"}
selectedDate={modelData.autumn_begin}
onChange={(data) => this.setFormDataAndError('autumn_begin', data, 'date')}
value={modelData.autumn_begin}
formManager={this}
fieldMapping={'autumn_begin'}
/>
<DateField label={"Date de fin du semestre d'automne"}
selectedDate={modelData.autumn_end}
onChange={(data) => this.setFormDataAndError('autumn_end', data, 'date')}
value={modelData.autumn_end}
formManager={this}
fieldMapping={'autumn_end'}
/>
<MarkdownField label={"Éventuel commentaire associé à ces informations"} maxLength={100}
value={modelData.comment}
onChange={(data) => this.setFormDataAndError('comment', data)}
formManager={this}
fieldMapping={'comment'}
/>
<UsefulLinksField label={"Lien(s) utile(s) (ex : vers ces informations)"}
value={modelData.UsefulLinksField}
onChange={(data) => this.setFormDataAndError('useful_links', data)}
value={modelData.useful_links}
formManager={this}
fieldMapping={'useful_links'}
/>
</div>
)
......
......@@ -12,6 +12,9 @@ import format from 'date-fns/format';
import KeyboardArrowLeftIcon from '@material-ui/icons/KeyboardArrowLeft';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import FieldWrapper from './FieldWrapper';
import dateToDateStr from '../../../../../utils/dateToDateStr';
import Field from './Field';
const styles = theme => ({
});
......@@ -23,31 +26,19 @@ class LocalizedUtils extends DateFnsUtils {
}
}
class DateField extends PureComponent {
hasError(date) {
return this.props.required && !date;
}
class DateField extends Field {
state = {
selectedDate: this.props.selectedDate,
hasError: this.hasError(this.props.selectedDate)
getValue() {
return dateToDateStr(this.state.value);
}
componentDidMount(){
// store the data in formData
this.handleDateChange(this.props.selectedDate);
hasError(date) {
return this.props.required && !date;
}
handleDateChange = (date) => {
const newState = {
selectedDate: date,
hasError: this.hasError(date)
}
this.setState(newState);
this.props.onChange({
data: newState.selectedDate,
hasError: newState.hasError
this.setState({
value: date,
});
}
......@@ -64,7 +55,7 @@ class DateField extends PureComponent {
<DatePicker
clearable
format="d MMM YYYY"
value={this.state.selectedDate}
value={this.state.value}
onChange={this.handleDateChange}
clearLabel="vider"
cancelLabel="annuler"
......@@ -78,15 +69,11 @@ class DateField extends PureComponent {
}
DateField.defaultProps = {
required: false,
label: 'mon label',
selectedDate: null,
onChange: (date) => console.log('Nouvelle date sélectionnée : ', date),
value: null,
}
DateField.propTypes = {
selectedDate: PropTypes.instanceOf(Date),
onChange: PropTypes.func.isRequired,
value: PropTypes.instanceOf(Date),
};
......
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
class Field extends PureComponent {
state = {
value: this.props.value,
hasError: this.hasError(this.props.value)
};
setState(newState) {
newState.hasError = this.hasError(newState.value);
super.setState(newState);
}
hasError() {
throw Error('This methods has to be override in sub classes')
}
getValue() {
// function to get the value, ready to send to server
// You might need to override this for weird formats such as Date.
return this.state.value;
}
getHasError() {
return this.state.hasError;
}
componentDidMount() {
this.props.formManager.addField(this, this.props.fieldMapping);
}
componentWillUnmount() {
this.props.formManager.removeField(this.props.fieldMapping);
}
}
Field.defaultProps = {
required: false,
label: 'mon label',
}
Field.propTypes = {
required: PropTypes.bool.isRequired,
label: PropTypes.string,
formManager: PropTypes.object.isRequired,
fieldMapping: PropTypes.string.isRequired
};
export default Field;
......@@ -12,20 +12,12 @@ import Typography from '@material-ui/core/Typography';
import Markdown from '../../../../shared/Markdown';
import LinkText from '../../../../other/TextLink';
import Field from './Field';
const styles = theme => ({
})
class MarkdownField extends React.Component {
state = {
value: this.props.value,
hasError: this.hasError(this.props.value)
};
componentDidMount() {
// store the data in formData
this.handleChangeValue(this.props.value);
}
class MarkdownField extends Field {
hasError(value) {
if (this.props.required && value == '') {
......@@ -44,21 +36,12 @@ class MarkdownField extends React.Component {
if (maxLength && value.length > maxLength + 1) {
value = value.substring(0, maxLength + 1);
}
const newState = {
value,
hasError: this.hasError(value)
}
this.setState(newState);
this.props.onChange({
data: newState.value,
hasError: newState.hasError
});
this.setState({ value });
}
render() {
const { classes } = this.props;
return (
<FieldWrapper
required={this.props.required}
......@@ -110,16 +93,12 @@ class MarkdownField extends React.Component {
MarkdownField.defaultProps = {
required: false,
value: '',
label: 'mon label',
maxLength: 0,
}
MarkdownField.propTypes = {
required: PropTypes.bool,
value: PropTypes.string,
label: PropTypes.string,
maxLength: PropTypes.number
};
......
......@@ -11,36 +11,20 @@ import Select from '@material-ui/core/Select';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import Field from './Field';
const styles = theme => ({
})
class SelectField extends React.Component {
state = {
value: this.props.value,
hasError: this.hasError(this.props.value)
};
class SelectField extends Field {
hasError(value) {
if (this.props.required && !value) {
return true;
} else {
return false;
}
return this.props.required && !value;
}
handleChangeValue = (value) => {
const newState = {
value,
hasError: this.hasError(value)
}
this.setState(newState);
this.props.onChange({
data: newState.value,
hasError: newState.hasError
})
this.setState({ value });
}
render() {
const { classes } = this.props;
return (
......@@ -68,22 +52,16 @@ class SelectField extends React.Component {
SelectField.defaultProps = {
required: false,
value: null,
label: 'mon label',
onChange: (data) => console.log('Nouvelle sélection : ', data),
}
SelectField.propTypes = {
required: PropTypes.bool,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
options: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.number.isRequired, PropTypes.string.isRequired]),
disabled: PropTypes.bool
})),
label: PropTypes.string,
onChange: PropTypes.func.isRequired,
};
......
......@@ -8,16 +8,12 @@ import FieldWrapper from './FieldWrapper';
import { TextField as MuiTextField } from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import Field from './Field';
const styles = theme => ({
})
class TextField extends React.Component {
state = {
value: this.props.value,
hasError: this.hasError(this.props.value)
};
class TextField extends Field {
hasError(value) {
if (this.props.required && value == '') {
return true;
......@@ -36,15 +32,7 @@ class TextField extends React.Component {
value = value.substring(0, maxLength + 1);
}
const newState = {
value,
hasError: this.hasError(value)
}
this.setState(newState);
this.props.onChange({
data: newState.value,
hasError: newState.hasError
})
this.setState({ value });
}
......@@ -78,19 +66,13 @@ class TextField extends React.Component {
TextField.defaultProps = {
required: false,
value: '',
label: 'mon label',
maxLength: 0,
onChange: (data) => console.log('Nouveau texte : ', data),
}
TextField.propTypes = {
required: PropTypes.bool,
value: PropTypes.string,
label: PropTypes.string,
maxLength: PropTypes.number,
onChange: PropTypes.func.isRequired,
};
......
......@@ -14,6 +14,7 @@ import Button from '@material-ui/core/Button';
import DeleteIcon from '@material-ui/icons/Delete';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
import Field from './Field';
const styles = theme => ({
container: {
......@@ -26,18 +27,7 @@ const styles = theme => ({
}
})
class UsefulLinksField extends React.Component {
state = {
usefulLinks: this.props.usefulLinks,
hasError: this.hasError(this.props.usefulLinks),
errorMessage: '',
}
componentDidMount() {
// store the data in formData
this.updateUsefulLinks(this.props.usefulLinks);
}
class UsefulLinksField extends Field {
hasError(usefulLinks) {
if (this.props.required && usefulLinks.length == 0) {
......@@ -47,21 +37,14 @@ class UsefulLinksField extends React.Component {
// TODO MORE
}
updateUsefulLinks(newUsefullLinks) {
const newState = {
usefulLinks: newUsefullLinks,
hasError: this.hasError(newUsefullLinks)
}
this.setState(newState);
this.props.onChange({
data: newState.usefulLinks,
hasError: newState.hasError
updateUsefulLinks(newUsefulLinks) {
this.setState({
value: newUsefulLinks,
});
}
handleUsefulLinkUrlChange = (idx, evt) => {
const newUsefulLinks = this.state.usefulLinks.map((usefulLink, sidx) => {
const newUsefulLinks = this.state.value.map((usefulLink, sidx) => {
if (idx !== sidx) { return usefulLink; }
return { ...usefulLink, url: evt.target.value };
});
......@@ -70,7 +53,7 @@ class UsefulLinksField extends React.Component {
}
handleUsefulLinkDescriptionChange = (idx, evt) => {
const newUsefulLinks = this.state.usefulLinks.map((usefulLink, sidx) => {
const newUsefulLinks = this.state.value.map((usefulLink, sidx) => {
if (idx !== sidx) { return usefulLink; }
return { ...usefulLink, description: evt.target.value };
});
......@@ -80,27 +63,27 @@ class UsefulLinksField extends React.Component {
handleAddUsefulLink = () => {
this.updateUsefulLinks(this.state.usefulLinks.concat([{ url: '', description: '' }]));
this.updateUsefulLinks(this.state.value.concat([{ url: '', description: '' }]));
}
handleSwipeUsefulLink = (idx, swipeIndexDiff) => {
const { usefulLinks } = this.state;
let newUsefulLinks = usefulLinks.slice();
const { value } = this.state;
let newUsefulLinks = value.slice();
const b = usefulLinks[idx + swipeIndexDiff];
const b = value[idx + swipeIndexDiff];
newUsefulLinks[idx + swipeIndexDiff] = newUsefulLinks[idx];
newUsefulLinks[idx] = b;
this.updateUsefulLinks(newUsefulLinks);
}
handleRemoveUsefulLink = (idx) => {
this.updateUsefulLinks(this.state.usefulLinks.filter((s, sidx) => idx !== sidx));
this.updateUsefulLinks(this.state.value.filter((s, sidx) => idx !== sidx));
}
areAllUsefulLinksUsed = () => {
const { usefulLinks } = this.state;
for (let idx in usefulLinks) {
const el = usefulLinks[idx];
const { value } = this.state;
for (let idx in value) {
const el = value[idx];
if (el.url == '' || el.description == '') {
return false;
}
......@@ -111,7 +94,7 @@ class UsefulLinksField extends React.Component {
render() {
const { classes } = this.props;
const nbOfUsefulLinks = this.state.usefulLinks.length;
const nbOfUsefulLinks = this.state.value.length;
return (
<FieldWrapper
required={this.props.required}
......@@ -125,7 +108,7 @@ class UsefulLinksField extends React.Component {
justify="flex-start"
alignItems="flex-start"
>
{this.state.usefulLinks.map((