Commit 6dfa5edc authored by Florent Chehab's avatar Florent Chehab

UniversityScholarship editor ok

parent 7aeec929
Pipeline #27360 passed with stages
in 2 minutes and 54 seconds
# Generated by Django 2.0.3 on 2018-09-16 14:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('backend', '0002_auto_20180916_1555'),
]
operations = [
migrations.AlterField(
model_name='countryscholarship',
name='frequency',
field=models.CharField(blank=True, choices=[('w', 'week'), ('m', 'month'), ('s', 'semester'), ('y', 'year'), ('o', 'one_shot')], default='m', max_length=1, null=True),
),
migrations.AlterField(
model_name='universityscholarship',
name='frequency',
field=models.CharField(blank=True, choices=[('w', 'week'), ('m', 'month'), ('s', 'semester'), ('y', 'year'), ('o', 'one_shot')], default='m', max_length=1, null=True),
),
]
......@@ -17,12 +17,15 @@ class Scholarship(BasicModule):
type = models.CharField(max_length=200)
currency = models.ForeignKey(Currency, null=True, on_delete=models.PROTECT)
other_advantages = models.CharField(default='', blank=True, max_length=5000)
other_advantages = models.CharField(
default='', blank=True, max_length=5000)
frequency = models.CharField(
max_length=1,
choices=SCHOLARSHIP_FREQUENCIES,
default='m',
null=True,
blank=True,
)
amount_min = models.DecimalField(
......
......@@ -12,7 +12,7 @@ import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import { lighten, darken } from '@material-ui/core/styles/colorManipulator';
import { Divider } from '@material-ui/core';
import Divider from '@material-ui/core/Divider';
import LinkText from '../other/TextLink';
const styles = (theme) => {
......
......@@ -20,17 +20,60 @@ const styles = theme => ({
...editorStyle(theme)
});
const frequencyOptions = [
{ value: 'w', label: "Il s'agit du montant hebdomadaire" },
{ value: 'm', label: "Il s'agit du montant mensuel" },
{ value: 's', label: "Il s'agit du montant semestriel" },
{ value: 'y', label: "Il s'agit du montant annuel" },
{ value: 'o', label: "Il s'agit d'un montant donné une seule fois" }
]
class UniversityScholarshipsEditor extends Editor {
formHasError() {
let messages = Array();
const formData = this.getDataFromFields();
const { amount_min, amount_max } = formData;
console.log(formData);
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.")
}
return this.buildError(messages);
}
renderEditor() {
const { modelData } = this.props;
return (
<div>
{this.renderObjModerationLevelField()}
{this.renderTitleField()}
{this.renderUniversitiesField()}
{this.renderTextField({
required: true,
label: "Présentation succincte",
maxLength: 200,
fieldMapping: 'type',
})}
{this.renderCurrencyField({ label: "Devise", required: false, fieldMapping: 'currency' })}
{this.renderNumberField({
label: "Borne inférieure du montant de la bourse",
minValue: 0,
fieldMapping: 'amount_min',
})}
{this.renderNumberField({
label: "Borne supérieure du montant de la bourse",
minValue: 0,
fieldMapping: 'amount_max',
})}
{this.renderSelectField({
label: "Fréquence de la bourse",
options: frequencyOptions,
fieldMapping: 'frequency',
})}
{this.renderMarkdownField({
label: "Autres avantages",
maxLength: 500,
formManager: this,
fieldMapping: 'other_advantages',
})}
{this.renderCommentField()}
{this.renderUsefulLinksField()}
</div>
......
......@@ -94,7 +94,7 @@ class UniversityScholarships extends MyComponent {
editor={UniversityScholarshipsEditor}
invalidateGroup={this.props.invalidateData}
propsForEditor={{
modelData: { universities: [this.props.univId], importance_level: '-' },
modelData: { universities: [this.props.univId], importance_level: '-', currency: 'EUR', obj_moderation_level: 0 },
parseRawModelData: parseRawModelData,
outsideData: outsideData,
__apiAttr: this.props.univId,
......
......@@ -19,6 +19,7 @@ import UsefulLinksField from './fields/UsefulLinksField';
import MarkdownField from './fields/MarkdownField';
import TextField from './fields/TextField';
import MultiSelectField from './fields/MultiSelectField';
import NumberField from './fields/NumberField';
import __map from 'lodash/map';
......@@ -297,31 +298,54 @@ class Editor extends MyComponent {
)
}
renderCommentField() {
const { comment } = this.props.modelData;
renderMarkdownField(props) {
return (
<MarkdownField label={"Commentaire associé à ces informations"}
maxLength={100}
value={comment}
<MarkdownField
{...this.addValueToProps(props)}
formManager={this}
fieldMapping={'comment'}
/>
)
}
renderTitleField() {
const { title } = this.props.modelData;
renderCommentField() {
const { comment } = this.props.modelData;
return this.renderMarkdownField({
label: "Commentaire associé à ces informations",
maxLength: 500,
value: comment,
formManager: this,
fieldMapping: 'comment',
})
}
addValueToProps(props){
if (typeof props.value == 'undefined'){
return Object.assign(props, {value: this.props.modelData[props.fieldMapping]})
} else {
return props;
}
}
renderTextField(props) {
return (
<TextField label={"Titre"}
required={true}
value={title}
maxLength={150}
<TextField
{...this.addValueToProps(props)}
formManager={this}
fieldMapping={'title'}
/>
)
}
renderTitleField() {
const { title } = this.props.modelData;
return this.renderTextField({
label: 'Titre',
required: true,
value: title,
maxLength: 150,
fieldMapping: 'title',
})
}
renderUniversitiesField() {
const { modelData } = this.props;
const { outsideData } = this.props;
......@@ -358,6 +382,36 @@ class Editor extends MyComponent {
)
}
renderSelectField(props) {
return (
<SelectField
{...this.addValueToProps(props)}
formManager={this}
/>
)
}
renderCurrencyField(props) {
const { outsideData } = this.props;
const currencies = __map(outsideData.currencies,
(c) => { return { label: c.code, value: c.code, disabled: false } }
)
return this.renderSelectField({
...props,
options: currencies,
})
}
renderNumberField(props) {
return (
<NumberField
{...this.addValueToProps(props)}
formManager={this}
/>
)
}
myRender() {
const { classes } = this.props;
return (
......
......@@ -119,7 +119,7 @@ class Scholarship extends React.Component {
<div>
<Typography className={classes.item} variant='headline' > Autre(s) avantage(s) : </Typography>
{
otherAdvantages != '' ?
otherAdvantages != '' && otherAdvantages !== null?
<Markdown source={otherAdvantages} />
:
<Typography variant='caption'><em>Aucun autre avantage a été notifié.</em></Typography>
......@@ -147,10 +147,10 @@ Scholarship.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
currency: PropTypes.string.isRequired,
frequency: PropTypes.string.isRequired,
frequency: PropTypes.string,
type: PropTypes.string.isRequired,
comment: PropTypes.string.isRequired,
otherAdvantages: PropTypes.string.isRequired,
otherAdvantages: PropTypes.string,
amountMin: PropTypes.string,
amountMax: PropTypes.string,
};
......
......@@ -2,10 +2,19 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
class Field extends PureComponent {
state = {
value: this.props.value,
error: this.hasError(this.props.value)
};
constructor(props) {
super(props);
let { value } = props;
if (typeof this.defaultNullValue !== 'undefined' && value === null) {
value = this.defaultNullValue;
}
this.state = {
value: value,
error: this.hasError(value)
};
}
setState(newState) {
newState.error = this.hasError(newState.value);
......
......@@ -18,6 +18,7 @@ const styles = theme => ({
})
class MarkdownField extends Field {
defaultNullValue = '';
hasError(value) {
let messages = Array();
......
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';
import Field from './Field';
const styles = theme => ({
})
class NumberField extends Field {
defaultNullValue = '';
getValue() {
const { value } = this.state;
if (value === '') {
return null;
} else {
return value;
}
}
hasError(value) {
let messages = Array();
if (this.props.required && value == '') {
messages.push("Ce champ est requis mais il est vide.");
}
if (this.props.maxValue && value > this.props.maxValue) {
messages.push("Le nombre inscrit est trop grand.");
}
if (this.props.minValue && value < this.props.minValue) {
messages.push("Le nombre inscrit est trop petit.");
}
return this.buildError(messages)
}
handleChangeValue = (val) => {
var regex = /[^\d\.]*/gi;
const value = val.replace(regex, '');
this.setState({ value });
}
renderInfo() {
const { minValue, maxValue } = this.props;
if (maxValue !== null && minValue !== null) {
return <Typography variant='caption'>Un nombre compris entre {minValue} et {maxValue} est attendu.</Typography>
} else if (minValue !== null) {
return <Typography variant='caption'>Un nombre supérieur ou égale à {minValue} est attendu.</Typography>
} else if (maxValue !== null) {
return <Typography variant='caption'>Un nombre inférieur ou égale à {maxValue} est attendu.</Typography>
} else {
return <div></div>
}
}
render() {
const { classes } = this.props;
return (
<FieldWrapper
required={this.props.required}
hasError={this.state.error.status}
errors={this.state.error.messages}
label={this.props.label}
>
{this.renderInfo()}
<TextField
placeholder={"Le champ est vide"}
fullWidth={true}
multiline={false}
value={this.state.value}
onChange={(e) => this.handleChangeValue(e.target.value)}
/>
</FieldWrapper>
)
}
}
NumberField.defaultProps = {
value: '',
maxValue: null,
minValue: null,
}
NumberField.propTypes = {
value: PropTypes.string,
maxValue: PropTypes.number,
minValue: PropTypes.number,
};
export default compose(
withStyles(styles, { withTheme: true }),
)(NumberField);
\ No newline at end of file
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 as MuiTextField } from '@material-ui/core';
import MuiTextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import Markdown from '../../../shared/Markdown';
import LinkText from '../../../other/TextLink';
import Field from './Field';
import isUrl from '../../../../utils/isUrl';
import stringHasExtension from '../../../../utils/stringHasExtension';
......@@ -20,13 +16,14 @@ const styles = theme => ({
})
class TextField extends Field {
defaultNullValue = '';
hasError(value) {
let messages = Array();
if (this.props.required && value == '') {
messages.push("Ce champ est requis mais il est vide.");
}
if (this.props.maxLength && value.length > this.props.maxLength) {
if (this.props.maxLength && value !== null && value.length > this.props.maxLength) {
messages.push("L'URL est trop long.");
}
if (this.props.isUrl && value != '' && !isUrl(value)) {
......
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