Validate expense/reimbursement forms

Adds some general helpers and styles for minimalistic form validation.
This commit is contained in:
2020-09-29 18:37:55 +02:00
parent 326d46b1a1
commit 444ec62a66
9 changed files with 114 additions and 45 deletions
+45 -11
View File
@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import moment from 'moment';
import isValidAmount from 'kredits-web/utils/is-valid-amount';
export default class AddExpenseItemComponent extends Component {
// @tracked newExpense = Expense.create();
@@ -22,6 +23,14 @@ export default class AddExpenseItemComponent extends Component {
{ code: 'GBP' }
];
get isValidAmount () {
return isValidAmount(this.amount);
}
get amountInputClass () {
return this.isValidTotal ? 'valid' : '';
}
get submitButtonEnabled () {
return true;
}
@@ -30,6 +39,27 @@ export default class AddExpenseItemComponent extends Component {
return !this.submitButtonEnabled;
}
validateForm () {
const formEl = document.querySelector('form#add-expense-item');
let validity = true;
if (!this.isValidAmount) {
document.querySelector('input[name=expense-amount]').classList.add('invalid');
validity = false;
}
if (!formEl.checkValidity()) {
document.querySelectorAll('form#add-expense-item input').forEach(i => {
if (!i.validity.valid) {
i.classList.add('invalid');
validity = false;
}
})
}
return validity;
}
@action
submit (e) {
e.preventDefault();
@@ -38,17 +68,21 @@ export default class AddExpenseItemComponent extends Component {
this.date[0] : this.date;
const [ date ] = dateInput.toISOString().split('T');
// TODO validate form
const expense = {
amount: parseFloat(this.amount),
currency: this.currency,
date: date,
title: this.title,
description: this.description,
url: this.url,
tags: this.tags.split(',').map(t => t.trim())
}
const isValid = this.validateForm();
this.args.addExpenseItem(expense);
if (isValid) {
const expense = {
amount: parseFloat(this.amount),
currency: this.currency,
date: date,
title: this.title,
description: this.description,
url: this.url,
tags: this.tags.split(',').map(t => t.trim())
}
this.args.addExpenseItem(expense);
} else {
return false;
}
}
}
+13 -5
View File
@@ -1,10 +1,15 @@
<form id="add-expense-item" onsubmit={{action "submit"}}>
<form id="add-expense-item" onsubmit={{action "submit"}} novalidate>
<fieldset class="horizontal">
<label>
<p class="label">Amount:</p>
<p>
{{input name="expense-amount" type="text"
placeholder="10" value=this.amount}}
{{input name="expense-amount"
type="text"
placeholder="10"
value=this.amount
required=true
pattern="([0-9]*[.])?[0-9]+"
class=this.amountInputClass}}
</p>
</label>
<label>
@@ -35,7 +40,10 @@
<label>
<p class="label">Title:</p>
<p>
{{input name="expense-title" type="text" value=this.title}}
{{input name="expense-title"
type="text"
value=this.title
required=true}}
</p>
</label>
<label>
@@ -47,7 +55,7 @@
<label>
<p class="label">URL (optional):</p>
<p>
{{input name="expense-url" type="text" value=this.url}}
{{input name="expense-url" type="url" value=this.url}}
</p>
</label>
<label>
@@ -6,6 +6,7 @@ import { action } from '@ember/object';
import { A } from '@ember/array';
import { scheduleOnce } from '@ember/runloop';
import Reimbursement from 'kredits-web/models/reimbursement';
import isValidAmount from 'kredits-web/utils/is-valid-amount';
export default class AddReimbursementComponent extends Component {
@service kredits;
@@ -19,12 +20,11 @@ export default class AddReimbursementComponent extends Component {
@tracked expenseFormVisible = true;
get isValidTotal () {
const amount = parseFloat(this.total);
if (Number.isNaN(amount)) {
return false;
} else {
return amount > 0;
}
return isValidAmount(this.total);
}
get totalInputClass () {
return this.isValidTotal ? 'valid' : '';
}
get submitButtonEnabled () {
@@ -1,4 +1,4 @@
<form onsubmit={{action "submit"}}>
<form onsubmit={{action "submit"}} novalidate>
<label>
<p class="label">Contributor:</p>
<p>
@@ -13,7 +13,12 @@
<label>
<p class="label">Total amount (WBTC):</p>
<p>
{{input type="text" placeholder="500" value=this.total}}
{{input type="text"
placeholder="500"
value=this.total
required=true
pattern="([0-9]*[.])?[0-9]+"
class=this.totalInputClass}}
</p>
</label>
+5 -2
View File
@@ -58,7 +58,7 @@ section#signup {
}
}
input[type=text], select {
input[type=text], input[type=url], select {
width: 100%;
padding: 1rem;
border: none;
@@ -72,12 +72,15 @@ section#signup {
&:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6);
}
&:focus {
&:focus :not(:invalid) {
border-color: $blue;
}
&::placeholder {
color: rgba(238, 238, 238, 0.5);
}
&.invalid {
border-color: $red;
}
}
select {
+8
View File
@@ -0,0 +1,8 @@
export default function isValidAmount(inputAmount) {
const amount = parseFloat(inputAmount);
if (Number.isNaN(amount)) {
return false;
} else {
return amount > 0;
}
}