Commit 13efd6d2 authored by Nicolas Frandeboeuf's avatar Nicolas Frandeboeuf
Browse files

Fix string ref (fix #487) + errors not localized

parent 4bad6d65
Pipeline #14218 passed with stage
in 3 minutes and 8 seconds
......@@ -59,7 +59,7 @@
react/no-set-state:
- 0
react/no-string-refs:
- 1 # TODO 2
- 2
react/no-unescaped-entities:
- 2
react/no-unknown-property:
......
......@@ -23,6 +23,10 @@ class CategoryListItem extends React.Component {
this.handleSave = this.handleSave.bind(this);
this.handleColorSave = this.handleColorSave.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.colorInput = null;
this.titleInput = null;
this.replacementSelector = null;
}
isEditing() {
......@@ -38,7 +42,7 @@ class CategoryListItem extends React.Component {
return this.handleSave(e);
} else if (e.key === 'Escape') {
if (this.isEditing()) {
this.refs.title.value = this.props.cat.title;
e.target.value = this.props.cat.title;
} else {
this.props.onCancelCreation(e);
}
......@@ -47,21 +51,21 @@ class CategoryListItem extends React.Component {
}
handleColorSave(e) {
if (this.isEditing() || this.refs.title.value.trim().length) {
if (this.isEditing() || this.titleInput.value.trim().length) {
this.handleSave(e);
}
}
handleSave(e) {
let cat = this.props.cat;
let title = this.refs.title.value.trim();
let color = this.refs.color.getValue();
let title = this.titleInput.value.trim();
let color = this.colorInput.getValue();
if (!title || !color || ((color === cat.color) && (title === cat.title))) {
if (this.isCreating()) {
this.props.onCancelCreation(e);
} else if (!this.title) {
this.refs.title.value = this.props.cat.title;
this.titleInput.value = this.props.cat.title;
}
return false;
......@@ -76,7 +80,7 @@ class CategoryListItem extends React.Component {
this.props.updateCategory(cat, category);
} else {
this.props.createCategory(category);
this.refs.title.value = '';
this.titleInput.value = '';
this.props.onCancelCreation(e);
}
......@@ -93,7 +97,7 @@ class CategoryListItem extends React.Component {
handleDelete(e) {
if (this.isEditing()) {
let replaceCategory = this.refs.replacement.value;
let replaceCategory = this.replacementSelector.value;
this.props.deleteCategory(this.props.cat, replaceCategory);
} else {
this.props.onCancelCreation(e);
......@@ -101,7 +105,7 @@ class CategoryListItem extends React.Component {
}
selectTitle() {
this.refs.title.select();
this.titleInput.select();
}
render() {
......@@ -143,6 +147,9 @@ class CategoryListItem extends React.Component {
title={ $t('client.general.delete') }
/>);
let replacementSelectorCb = selector => {
this.replacementSelector = selector;
};
let modalBody = (<div>
<div className="alert alert-info">
{ $t('client.category.erase', { title: c.title }) }
......@@ -150,7 +157,7 @@ class CategoryListItem extends React.Component {
<div>
<select
className="form-control"
ref="replacement">
ref={ replacementSelectorCb }>
{ replacementOptions }
</select>
</div>
......@@ -163,13 +170,20 @@ class CategoryListItem extends React.Component {
/>);
}
let colorInputCb = input => {
this.colorInput = input;
};
let titleInputCb = input => {
this.titleInput = input;
};
return (
<tr key={ c.id }>
<td>
<ColorPicker
defaultValue={ c.color }
onChange={ this.handleColorSave }
ref="color"
ref={ colorInputCb }
/>
</td>
<td>
......@@ -180,7 +194,7 @@ class CategoryListItem extends React.Component {
defaultValue={ c.title }
onKeyUp={ this.handleKeyUp }
onBlur={ this.handleBlur }
ref="title"
ref={ titleInputCb }
/>
</td>
<td>
......
......@@ -55,10 +55,16 @@ class OperationsComponent extends React.Component {
this.operationHeight = computeOperationHeight();
this.selectModalOperation = this.selectModalOperation.bind(this);
this.detailsModal = null;
this.wells = null;
this.search = null;
this.panelHeading = null;
this.thead = null;
}
selectModalOperation(operationId) {
this.refs.detailsModal.setOperationId(operationId);
this.detailsModal.setOperationId(operationId);
}
// Implementation of infinite list.
......@@ -87,10 +93,10 @@ class OperationsComponent extends React.Component {
}
handleWindowResize() {
let wellH = ReactDOM.findDOMNode(this.refs.wells).scrollHeight;
let searchH = ReactDOM.findDOMNode(this.refs.search).scrollHeight;
let panelH = ReactDOM.findDOMNode(this.refs.panelHeading).scrollHeight;
let theadH = ReactDOM.findDOMNode(this.refs.thead).scrollHeight;
let wellH = ReactDOM.findDOMNode(this.wells).scrollHeight;
let searchH = ReactDOM.findDOMNode(this.search).scrollHeight;
let panelH = ReactDOM.findDOMNode(this.panelHeading).scrollHeight;
let theadH = ReactDOM.findDOMNode(this.thead).scrollHeight;
this.heightAbove = wellH + searchH + panelH + theadH;
......@@ -135,10 +141,26 @@ class OperationsComponent extends React.Component {
let negativeSum = computeTotal(format, x => x.amount < 0, wellOperations, 0);
let sum = computeTotal(format, () => true, wellOperations, 0);
let detailsModalCb = node => {
this.detailsModal = node;
};
let wellsCb = node => {
this.wells = node;
};
let searchCb = node => {
this.search = node;
};
let panelHeadingCb = node => {
this.panelHeading = node;
};
let theadCb = node => {
this.thead = node;
};
return (
<div>
<DetailsModal
ref="detailsModal"
ref={ detailsModalCb }
formatCurrency={ format }
categories={ this.props.categories }
types={ this.props.types }
......@@ -147,7 +169,7 @@ class OperationsComponent extends React.Component {
<div
className="row operation-wells"
ref="wells">
ref={ wellsCb }>
<AmountWell
backgroundColor={ wellsColors.BALANCE }
......@@ -186,12 +208,12 @@ class OperationsComponent extends React.Component {
/>
</div>
<SearchComponent ref="search" />
<SearchComponent ref={ searchCb } />
<div className="operation-panel panel panel-default">
<div
className="panel-heading"
ref="panelHeading">
ref={ panelHeadingCb }>
<h3 className="title panel-title">
{ $t('client.operations.title') }
</h3>
......@@ -200,7 +222,7 @@ class OperationsComponent extends React.Component {
<div className="table-responsive">
<table className="table table-hover table-bordered">
<thead ref="thead">
<thead ref={ theadCb }>
<tr>
<th className="hidden-xs" />
<th className="col-sm-1 col-xs-2">
......
......@@ -31,13 +31,17 @@ class SearchComponent extends React.Component {
this.handleToggleDetails = this.handleToggleDetails.bind(this);
this.handleClearSearchNoClose = this.handleClearSearch.bind(this, false);
this.handleClearSearchAndClose = this.handleClearSearch.bind(this, true);
this.searchForm = null;
this.lowAmountInput = null;
this.highAmountInput = null;
}
handleClearSearch(close, event) {
this.setState({ showDetails: !close });
this.refs.searchForm.reset();
this.refs.amount_low.clear();
this.refs.amount_high.clear();
this.searchForm.reset();
this.lowAmountInput.clear();
this.highAmountInput.clear();
this.props.resetAll();
event.preventDefault();
}
......@@ -87,9 +91,15 @@ class SearchComponent extends React.Component {
)
);
let handleKeyword = () => this.props.setKeywords(this.refs.keywords.value);
let handleCategory = () => this.props.setCategoryId(this.refs.cat.value);
let handleOperationType = () => this.props.setType(this.refs.type.value);
let handleKeyword = event => {
this.props.setKeywords(event.target.value);
};
let handleCategory = event => {
this.props.setCategoryId(event.target.value);
};
let handleOperationType = event => {
this.props.setType(event.target.value);
};
let handleAmountLow = value => {
this.props.setAmountLow(Number.isNaN(value) ? null : value);
};
......@@ -98,10 +108,21 @@ class SearchComponent extends React.Component {
};
let handleDateLow = value => this.props.setDateLow(value);
let handleDateHigh = value => this.props.setDateHigh(value);
let searchFormCb = node => {
this.searchForm = node;
};
let lowAmountInputCb = node => {
this.lowAmountInput = node;
};
let highAmountInputCb = node => {
this.highAmountInput = node;
};
details = (
<form
className="panel-body transition-expand"
ref="searchForm">
ref={ searchFormCb }>
<Special />
......@@ -114,7 +135,6 @@ class SearchComponent extends React.Component {
className="form-control"
onKeyUp={ handleKeyword }
id="keywords"
ref="keywords"
/>
</div>
......@@ -130,8 +150,7 @@ class SearchComponent extends React.Component {
className="form-control"
id="category-selector"
defaultValue={ this.props.searchFields.categoryId }
onChange={ handleCategory }
ref="cat">
onChange={ handleCategory }>
{ catOptions }
</select>
</div>
......@@ -144,8 +163,7 @@ class SearchComponent extends React.Component {
<select
className="form-control"
id="type-selector"
onChange={ handleOperationType }
ref="type">
onChange={ handleOperationType }>
{ typeOptions }
</select>
</div>
......@@ -172,7 +190,7 @@ class SearchComponent extends React.Component {
<AmountInput
onChange={ handleAmountLow }
id="amount-low"
ref="amount_low"
ref={ lowAmountInputCb }
signId="search-sign-amount-low"
/>
</div>
......@@ -187,7 +205,7 @@ class SearchComponent extends React.Component {
<AmountInput
onChange={ handleAmountHigh }
id="amount-high"
ref="amount_high"
ref={ highAmountInputCb }
signId="search-sign-amount-high"
/>
</div>
......@@ -212,7 +230,6 @@ class SearchComponent extends React.Component {
</div>
<div className="col-xs-8 col-md-5">
<DatePicker
ref="date_low"
id="date-low"
key="date-low"
onSelect={ handleDateLow }
......@@ -229,7 +246,6 @@ class SearchComponent extends React.Component {
</div>
<div className="col-xs-8 col-md-4">
<DatePicker
ref="date_high"
id="date-high"
key="date-high"
onSelect={ handleDateHigh }
......
......@@ -11,52 +11,56 @@ class ImportModule extends React.Component {
super(props);
this.handleImport = this.handleImport.bind(this);
this.handleChange = this.handleChange.bind(this);
this.fileNameInput = null;
this.fileInput = null;
}
handleImport(e) {
let $importFile = document.getElementById('importFile');
if (!$importFile || !$importFile.files || !$importFile.files.length) {
if (!this.fileInput.files || !this.fileInput.files.length) {
alert($t('client.settings.no_file_selected'));
e.preventDefault();
return;
}
let fileReader = new FileReader;
let fileReader = new FileReader();
fileReader.onload = fileEvent => {
let asText = fileEvent.target.result;
let asJSON;
try {
asJSON = JSON.parse(asText);
this.props.importInstance(asJSON);
this.props.importInstance(JSON.parse(fileEvent.target.result));
} catch (err) {
if (err instanceof SyntaxError) {
alert('JSON file to import isnt valid!');
alert($t('client.settings.import_invalid_json'));
} else {
alert(`Unexpected error: ${err.message}`);
}
}
};
fileReader.readAsText($importFile.files[0]);
fileReader.readAsText(this.fileInput.files[0]);
$importFile.value = '';
this.refs.fileName.value = '';
this.fileInput.value = '';
this.fileNameInput.value = '';
e.preventDefault();
}
handleChange(e) {
this.refs.fileName.value = e.target.value;
this.fileNameInput.value = e.target.value;
}
render() {
let fileNameInputCb = input => {
this.fileNameInput = input;
};
let fileInputCb = input => {
this.fileInput = input;
};
return (
<div className="input-group import-file">
<input
type="text"
className="form-control"
readOnly={ true }
ref="fileName"
ref={ fileNameInputCb }
/>
<span className="input-group-btn">
......@@ -65,7 +69,7 @@ class ImportModule extends React.Component {
<input
type="file"
name="importFile"
id="importFile"
ref={ fileInputCb }
onChange={ this.handleChange }
/>
</div>
......@@ -73,7 +77,6 @@ class ImportModule extends React.Component {
<span className="input-group-btn">
<button
id="importInstance"
className="btn btn-primary"
onClick={ this.handleImport }>
{ $t('client.settings.go_import_instance') }
......
......@@ -31,6 +31,10 @@ class AddOperationModal extends React.Component {
this.handleSelectOperationType = type => this.setState({ type });
this.handleSelectCategory = id => this.setState({ categoryId: id });
this.dateInput = null;
this.titleInput = null;
this.amountInput = null;
}
handleOnSubmit(event) {
......@@ -62,9 +66,9 @@ class AddOperationModal extends React.Component {
}
clearOperation() {
this.refs.date.clear();
this.refs.title.clear();
this.refs.amount.clear();
this.dateInput.clear();
this.titleInput.clear();
this.amountInput.clear();
this.setState(this.makeClearState());
}
......@@ -81,6 +85,16 @@ class AddOperationModal extends React.Component {
let labelTitle = $t('client.addoperationmodal.label');
let labelAmount = $t('client.addoperationmodal.amount');
let dateInputCb = input => {
this.dateInput = input;
};
let titleInputCb = input => {
this.titleInput = input;
};
let amountInputCb = input => {
this.amountInput = input;
};
let modalBody = (
<div>
<span>
......@@ -96,7 +110,7 @@ class AddOperationModal extends React.Component {
onChange={ this.handleChangeDate }
inputID={ `date${this.props.account.id}` }
label={ labelDate }
ref="date"
ref={ dateInputCb }
/>
<div className="form-group">
......@@ -116,7 +130,7 @@ class AddOperationModal extends React.Component {
inputID={ `title${this.props.account.id}` }
onChange={ this.handleChangeLabel }
label={ labelTitle }
ref="title"
ref={ titleInputCb }
/>
<ValidatedAmountInput
......@@ -124,7 +138,7 @@ class AddOperationModal extends React.Component {
label={ labelAmount }
inputID={ `amount${this.props.account.id}` }
className="form-control"
ref="amount"
ref={ amountInputCb }
/>
<div className="form-group">
......
import React from 'react';
import { assertHas, translate as $t } from '../../../helpers';
import { translate as $t } from '../../../helpers';
export default class CustomBankField extends React.Component {
class CustomBankField extends React.Component {
constructor(props) {
assertHas(props, 'params');
super(props);
this.fieldInput = null;
}
getValue() {
let node = this.refs.field;
let node = this.fieldInput;
return {
name: this.props.params.name,
value: (this.props.params.type === 'number') ?
......@@ -21,6 +22,9 @@ export default class CustomBankField extends React.Component {
render() {
let customFieldFormInput, customFieldOptions, defaultValue;
let fieldInputCb = input => {
this.fieldInput = input;
};
switch (this.props.params.type) {
case 'select':
......@@ -37,7 +41,7 @@ export default class CustomBankField extends React.Component {
name={ this.props.params.name }
className="form-control"
id={ this.props.params.name }
ref="field"
ref={ fieldInputCb }
defaultValue={ defaultValue }>
{ customFieldOptions }
</select>
......@@ -53,7 +57,7 @@ export default class CustomBankField extends React.Component {
type={ this.props.params.type }
className="form-control"
id={ this.props.params.name }
ref="field"
ref={ fieldInputCb }
placeholder={ this.props.params.placeholderKey ?
$t(this.props.params.placeholderKey) :
'' }
......@@ -76,3 +80,10 @@ export default class CustomBankField extends React.Component {
);
}
}
CustomBankField.propTypes = {
// An object with parameters according to the type of custom field
params: React.PropTypes.object.isRequired
};
export default CustomBankField;
......@@ -10,18 +10,23 @@ class EditAccessModal extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.extractCustomFieldValue = this.extractCustomFieldValue.bind(this);
this.loginInput = null;
this.passwordInput = null;
this.customFieldsInputs = [];
}
extractCustomFieldValue(field, index) {
return this.refs[`customField${index}`].getValue();
return this.customFieldsInputs[index].getValue();
}
handleSubmit(event) {
event.preventDefault();
let newLogin = this.refs.login.value.trim();
let newPassword = this.refs.password.value.trim();
let newLogin = this.loginInput.value.trim();
let newPassword = this.passwordInput.value.trim();
if (!newPassword || !newPassword.length) {
alert($t('client.editaccessmodal.not_empty'));
return;
......@@ -37,25 +42,37 @@ class EditAccessModal extends React.Component {
}
this.props.onSave(newLogin, newPassword, customFields);
this.refs.password.value = '';
this.passwordInput.value = '';
$(`#${this.props.modalId}`).modal('hide');
}
render() {