Commit 6726073a authored by Florent Chehab's avatar Florent Chehab

Work on fields and cleaning

parent 50b55c85
......@@ -56,8 +56,7 @@ class FullScreenDialog extends React.Component {
</Toolbar>
</AppBar>
<Paper className={classes.paper}>
{/* {this.props.children} */}
<UniversitySemestersDatesEditor />
{this.props.children}
</Paper>
</Dialog>
</div>
......
......@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import compose from 'recompose/compose';
import {connect} from "react-redux";
import { connect } from "react-redux";
import Paper from '@material-ui/core/Paper';
import FullScreenDialog from '../../shared/FullScreenDialog';
......@@ -88,7 +88,13 @@ class GenericModule extends MyComponent {
const { classes } = this.props;
return (
<div>
<FullScreenDialog open={this.state.fullScreenDialogOpen} handleClose={this.handleCloseFullScreenDialog} />
<FullScreenDialog
open={this.state.fullScreenDialogOpen}
handleClose={this.handleCloseFullScreenDialog}
handleSave={this.props.handleSaveEditor}
>
{this.props.editor}
</FullScreenDialog>
<Paper className={classes.root} square={true}>
{renderFirstRow.bind(this)()}
......@@ -110,7 +116,7 @@ GenericModule.defaultProps = {
GenericModule.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
modelData: PropTypes.object.isRequired
rawModelData: PropTypes.object.isRequired
};
......
......@@ -2,7 +2,7 @@ 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 { connect } from "react-redux";
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
......@@ -19,7 +19,10 @@ import GenericModule from './GenericModule';
import MyComponent from '../../MyComponent';
import dateToStr from '../../../utils/dateToStr';
import dateStrToStr from '../../../utils/dateStrToStr';
import dateStrToDate from '../../../utils/dateStrToDate';
import UniversitySemestersDatesEditor from './editors/UniversitySemestersDatesEditor';
import {
universitiesSemestersDatesElFetchData,
......@@ -42,29 +45,60 @@ const styles = theme => ({
}
});
function convertDate(date) {
function convertDateStrToStr(date) {
if (date) {
return dateToStr(date);
return dateStrToStr(date);
} else {
return "Non connue."
}
}
function convertDateStrToDate(date) {
if (date) {
return dateStrToDate(date);
} else {
return null
}
}
class UniversitySemestersDates extends MyComponent {
idToUse = "univId";
parse(rawModelData) {
// reverse serialization
const semestersDates = this.getFetchedData('universitiesSemestersDatesEl');
let { autumn_begin, autumn_end, spring_begin, spring_end, comment, useful_links } = semestersDates;
const modelData = {
autumn_begin: convertDateStrToDate(autumn_begin),
autumn_end: convertDateStrToDate(autumn_end),
spring_begin: convertDateStrToDate(spring_begin),
spring_end: convertDateStrToDate(spring_end),
useful_links,
id,
comment
}
return modelData;
}
myRender() {
const { classes } = 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);
autumn_begin = convertDateStrToStr(autumn_begin);
autumn_end = convertDateStrToStr(autumn_end);
spring_begin = convertDateStrToStr(spring_begin);
spring_end = convertDateStrToStr(spring_end);
return (
<GenericModule title={"Date des semestres"} modelData={semestersDates}>
<GenericModule
title={"Date des semestres"}
rawModelData={semestersDates}
editor={<UniversitySemestersDatesEditor modelData={this.parse()} />}
>
<div className={classes.root}>
<Table >
<TableHead>
......@@ -125,7 +159,7 @@ const mapDispatchToProps = (dispatch) => {
return {
fetchData: {
universitiesSemestersDatesEl: (univId) => dispatch(universitiesSemestersDatesElFetchData(univId)),
}
},
};
};
......
......@@ -2,7 +2,7 @@ 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 { connect } from "react-redux";
import TextField from '@material-ui/core/TextField';
......@@ -11,26 +11,65 @@ import DateField from './fields/DateField';
import UsefulLinksField from './fields/UsefulLinksField';
import MarkdownField from './fields/MarkdownField';
// import dateToStr from '../../../utils/dateToStr';
// import {
// universitiesSemestersDatesElFetchData,
// } from '../../../generated/actions';
import {
universitiesSemestersDatesElSaveData
} from '../../../../generated/actions';
class UniversitySemestersDatesEditor extends MyComponent {
// idToUse = "univId";
constructor(props) {
super(props);
this.formData = {};
this.formError = {};
const {modelData} = this.props;
for (let fieldKey in modelData){
this.formData[fieldKey] = modelData[fieldKey];
this.formError[fieldKey] = modelData[fieldKey];
}
}
setFormDataAndError(field, data) {
this.formData[field] = data.data;
this.formError[field] = data.hasError;
}
handleSendToServer(data) {
this.props.saveData(formData);
}
myRender() {
const {modelData} = this.props;
return (
<div>
<DateField label={"Date de début du semestre de printemps :"} />
<DateField label={"Date de fin du semestre de printemps :"} />
<DateField label={"Date de début du semestre d'automne :"} />
<DateField label={"Date de fin du semestre d'automne :"} />
<MarkdownField />
<UsefulLinksField />
<DateField label={"Date de début du semestre de printemps"}
required={true}
selectedDate={modelData.spring_begin}
onChange={(data) => this.setFormDataAndError('spring_begin', data)}
/>
<DateField label={"Date de fin du semestre de printemps"}
selectedDate={modelData.spring_end}
onChange={(data) => this.setFormDataAndError('spring_end', data)}
/>
<DateField label={"Date de début du semestre d'automne"}
selectedDate={modelData.autumn_begin}
onChange={(data) => this.setFormDataAndError('autumn_begin', data)}
/>
<DateField label={"Date de fin du semestre d'automne"}
selectedDate={modelData.autumn_end}
onChange={(data) => this.setFormDataAndError('autumn_end', data)}
/>
<MarkdownField label={"Éventuel commentaire associé à ces informations"} maxLength={100}
value={modelData.comment}
onChange={(data) => this.setFormDataAndError('comment', data)}
/>
<UsefulLinksField label={"Lien(s) utile(s) (ex : vers ces informations)"}
value={modelData.UsefulLinksField}
onChange={(data) => this.setFormDataAndError('useful_links', data)}
/>
</div>
)
}
......@@ -38,28 +77,21 @@ class UniversitySemestersDatesEditor extends MyComponent {
// UniversitySemestersDatesEditor.propTypes = {
// classes: PropTypes.object.isRequired,
// theme: PropTypes.object.isRequired,
// univId: PropTypes.string.isRequired
// };
UniversitySemestersDatesEditor.propTypes = {
modelData: PropTypes.object.isRequired,
};
// const mapStateToProps = (state) => {
// return {
// universitiesSemestersDatesEl: state.universitiesSemestersDatesEl,
// };
// };
const mapDispatchToProps = (dispatch) => {
return {
saveData: (data) => universitiesSemestersDatesElSaveData(data)
};
};
// const mapDispatchToProps = (dispatch) => {
// return {
// fetchData: {
// universitiesSemestersDatesEl: (univId) => dispatch(universitiesSemestersDatesElFetchData(univId)),
// }
// };
// };
export default compose(
// withStyles(styles, { withTheme: true }),
// connect(mapStateToProps, mapDispatchToProps)
connect(null, mapDispatchToProps)
)(UniversitySemestersDatesEditor);
\ No newline at end of file
......@@ -11,16 +11,9 @@ import format from 'date-fns/format';
import KeyboardArrowLeftIcon from '@material-ui/icons/KeyboardArrowLeft';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import { Typography } from '@material-ui/core';
import FieldWrapper from './FieldWrapper';
const styles = theme => ({
datePicker: {
// width: '300px',
},
picker: {
marginBottom: 3 * theme.spacing.unit
}
});
......@@ -31,23 +24,37 @@ class LocalizedUtils extends DateFnsUtils {
}
class DateField extends PureComponent {
hasError(date) {
return this.props.required && !date;
}
state = {
selectedDate: this.props.selectedDate,
hasError: this.hasError(this.props.selectedDate)
}
handleDateChange = (date) => {
this.setState({ selectedDate: date });
this.props.handleDateChange(date);
const newState = {
selectedDate: date,
hasError: this.hasError(date)
}
this.setState(newState);
this.props.onChange({
data: newState.selectedDate,
hasError: newState.hasError
});
}
render() {
const { classes } = this.props;
const { props } = this.props;
return (
<MuiPickersUtilsProvider utils={LocalizedUtils} locale={frLocale}>
<div className={classes.picker}>
<Typography color='textSecondary'>{this.props.label}</Typography>
<FieldWrapper
required={this.props.required}
hasError={this.state.hasError}
label={this.props.label}
>
<MuiPickersUtilsProvider utils={LocalizedUtils} locale={frLocale}>
<DatePicker
clearable
format="d MMM YYYY"
......@@ -57,24 +64,23 @@ class DateField extends PureComponent {
cancelLabel="annuler"
leftArrowIcon={<KeyboardArrowLeftIcon />}
rightArrowIcon={<KeyboardArrowRightIcon />}
className={classes.datePicker}
/>
</div>
</MuiPickersUtilsProvider>
</MuiPickersUtilsProvider>
</FieldWrapper >
);
}
}
DateField.defaultProps = {
selectedDate: Date.now(),
handleDateChange: (date) => console.log('Nouvelle date sélectionnée : ', date),
label: 'LABEL'
required: false,
label: 'mon label',
selectedDate: Date(),
onChange: (date) => console.log('Nouvelle date sélectionnée : ', date),
}
DateField.propTypes = {
selectedDate: PropTypes.instanceOf(Date).isRequired,
handleDateChange: PropTypes.func.isRequired,
label: PropTypes.string.isRequired
selectedDate: PropTypes.instanceOf(Date),
onChange: PropTypes.func.isRequired,
};
......
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import compose from 'recompose/compose';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';
const styles = theme => ({
formElement: {
marginBottom: 3 * theme.spacing.unit
}
});
class FieldWrapper extends PureComponent {
render() {
const { props } = this;
return (
<FormControl className={props.classes.formElement} required={props.required} error={props.hasError} fullWidth={true}>
<FormLabel>{props.label}</FormLabel>
{props.children}
</FormControl>
);
}
}
FieldWrapper.defaultProps = {
label: 'LABEL',
required: false,
hasError: false,
}
FieldWrapper.propTypes = {
label: PropTypes.string.isRequired,
required: PropTypes.bool.isRequired,
hasError: PropTypes.bool.isRequired,
};
export default compose(
withStyles(styles, { withTheme: true })
)(FieldWrapper);
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import Grid from '@material-ui/core/Grid';
import compose from 'recompose/compose';
import FieldWrapper from './FieldWrapper';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
......@@ -14,16 +17,32 @@ const styles = theme => ({
})
class MarkdownField extends React.Component {
constructor() {
super();
this.state = {
value: ''
};
state = {
value: this.props.value,
hasError: this.hasError(this.props.value)
};
hasError(value) {
if (this.props.required && value == '') {
return true;
} else if (this.props.maxLength && value.length > this.props.maxLength) {
return true;
} else {
return false;
}
}
handleChangeValue = (value) => {
handleChangeValue = (val) => {
let value = val;
const { maxLength } = this.props;
if (maxLength && value.length > maxLength + 1) {
value = value.substring(0, maxLength + 1);
}
this.setState({
value
value,
hasError: this.hasError(value)
});
}
......@@ -32,7 +51,11 @@ class MarkdownField extends React.Component {
const { classes } = this.props;
return (
<div>
<FieldWrapper
required={this.props.required}
hasError={this.state.hasError}
label={this.props.label}
>
<Grid
container
spacing={16}
......@@ -43,7 +66,19 @@ class MarkdownField extends React.Component {
(ce champ supporte en grande partie la syntaxe <LinkText href="https://www.markdownguide.org/basic-syntax">Markdown</LinkText>)
</em>
</Typography>
<TextField fullWidth={true} multiline={true} onChange={(e) => this.handleChangeValue(e.target.value)} />
{
this.props.maxLength ?
<Typography variant='caption'>Nombre de caractères : {this.state.value.length}/{this.props.maxLength}</Typography>
:
<div></div>
}
<TextField
placeholder={"Le champ est vide"}
fullWidth={true}
multiline={true}
value={this.state.value}
onChange={(e) => this.handleChangeValue(e.target.value)}
/>
</Grid>
......@@ -59,12 +94,27 @@ class MarkdownField extends React.Component {
</Grid>
</Grid>
</div>
</FieldWrapper>
)
}
}
MarkdownField.defaultProps = {
required: false,
value: '',
label: 'mon label',
maxLength: 0,
}
MarkdownField.propTypes = {
required: PropTypes.bool,
value: PropTypes.string,
label: PropTypes.string,
maxLength: PropTypes.number
};
export default compose(
withStyles(styles, { withTheme: true }),
)(MarkdownField);
\ No newline at end of file
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import compose from 'recompose/compose';
import FieldWrapper from './FieldWrapper';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
})
class TextField extends React.Component {
state = {
value: this.props.value,
hasError: this.hasError(this.props.value)
};
hasError(value) {
if (this.props.required && value == '') {
return true;
} else if (this.props.maxLength && value.length > this.props.maxLength) {
return true;
} else {
return false;
}
}
handleChangeValue = (val) => {
let value = val;
const { maxLength } = this.props;
if (maxLength && value.length > maxLength + 1) {
value = value.substring(0, maxLength + 1);
}
this.setState({
value,
hasError: this.hasError(value)
});
}
render() {
const { classes } = this.props;
return (
<FieldWrapper
required={this.props.required}
hasError={this.state.hasError}
label={this.props.label}
>
{
this.props.maxLength ?
<Typography variant='caption'>Nombre de caractères : {this.state.value.length}/{this.props.maxLength}</Typography>
:
<div></div>
}
<TextField
placeholder={"Le champ est vide"}
fullWidth={true}
value={this.state.value}
onChange={(e) => this.handleChangeValue(e.target.value)}
/>
</FieldWrapper>
)
}
}
TextField.defaultProps = {
required: false,
value: '',
label: 'mon label',
maxLength: 0,
}
TextField.propTypes = {
required: PropTypes.bool,
value: PropTypes.string,
label: PropTypes.string,
maxLength: PropTypes.number
};
export default compose(
withStyles(styles, { withTheme: true }),
)(TextField);
\ No newline at end of file
......@@ -4,6 +4,8 @@ import withStyles from '@material-ui/core/styles/withStyles';
import Grid from '@material-ui/core/Grid';
import compose from 'recompose/compose';
import FieldWrapper from './FieldWrapper';
import TextField from '@material-ui/core/TextField';
import IconButton from '@material-ui/core/IconButton';
import Button from '@material-ui/core/Button';
......@@ -24,13 +26,24 @@ const styles = theme => ({
})
class UsefulLinksField extends React.Component {
constructor() {
super();
this.state = {
usefulLinks: Array({ url: '', description: '' }),
};
state = {
usefulLinks: this.props.usefulLinks,
hasError: this.hasError(this.props.usefulLinks),
errorMessage: '',
}
hasError(usefulLinks) {
if (this.props.required && usefulLinks.length == 0) {
return true;
}
return false;
// TODO MORE
}
updateUsefulLinks(newUsefullLinks) {
this.setState({ usefulLinks: newUsefullLinks });
}
handleUsefulLinkUrlChange = (idx, evt) => {
const newUsefulLinks = this.state.usefulLinks.map((usefulLink, sidx) => {
......@@ -38,7 +51,7 @@ class UsefulLinksField extends React.Component {
return { ...usefulLink, url: evt.target.value };
});
this.setState({ usefulLinks: newUsefulLinks });
this.updateUsefulLinks(newUsefulLinks);
}
handleUsefulLinkDescriptionChange = (idx, evt) => {
......@@ -47,14 +60,12 @@ class UsefulLinksField extends React.Component {
return { ...usefulLink, description: evt.target.value };
});
this.setState({ usefulLinks: newUsefulLinks });
this.updateUsefulLinks(newUsefulLinks);
}
handleAddUsefulLink = () => {
this.setState({
usefulLinks: this.state.usefulLinks.concat([{ url: '', description: '' }])
});
this.updateUsefulLinks(this.state.usefulLinks.concat([{ url: '', description: '' }]));
}
handleSwipeUsefulLink = (idx, swipeIndexDiff) => {
......@@ -64,22 +75,18 @@ class UsefulLinksField extends React.Component {