updated settings/loan calculator/add transaction

Strengthened form validation in the settings page, fixing an input bug with whitespaces. Added form validation to the loan calculator and add transaction widgets
This commit is contained in:
danielq65 2023-04-28 10:57:16 -04:00
parent 461b05f1b6
commit 0125f6f9f7
3 changed files with 156 additions and 99 deletions

View file

@ -123,9 +123,27 @@ const AddExpenseForm = (props) => {
setCost(event.target.value)
}
(() => {
// Fetch all the forms we want to apply custom Bootstrap validation styles to
const forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated')
}, false)
})
})()
return (
<div className='widget'>
<h4>Add Transaction</h4>
<form className="needs-validation" onSubmit={onSubmit} noValidate>
<div style={{height: "85%"}} className='d-flex flex-column justify-content-between'>
<div className='row'>
<div className='col'>
@ -140,6 +158,9 @@ const AddExpenseForm = (props) => {
value={cost}
onChange={(event) => setCost(event.target.value)}
/>
<div className="invalid-feedback">
Please enter a valid amount
</div>
</div>
<div className='col'>
<label htmlFor='category-select'>Category</label>
@ -184,7 +205,7 @@ const AddExpenseForm = (props) => {
<button className='btn btn-dark m-right mt-2' onClick={toggleTransactionType}>
{transactionType.toUpperCase()}
</button>
<button type='submit' onClick={onSubmit} id="add-transaction-button" className='btn btn-primary m-right mt-2'>
<button type='submit' id="add-transaction-button" className='btn btn-primary m-right mt-2'>
Add Transaction
</button>
<button className='btn btn-primary mt-2' onClick={handleAddCategory}>
@ -193,6 +214,7 @@ const AddExpenseForm = (props) => {
</div>
</div>
</div>
</form>
</div>
);
};

View file

@ -8,7 +8,9 @@ const LoanCalculator = () => {
const [monthlyPayment, setMonthlyPayment] = useState(0);
const [interestPaid, setInterestPaid] = useState(0);
const calculateMonthlyPayment = () => {
const calculateMonthlyPayment = (event) => {
event.preventDefault();
const percentageToDecimal = (percent) => {
return percent / 12 / 100;
}
@ -24,21 +26,69 @@ const LoanCalculator = () => {
setInterestPaid(monthlyPayment * (loanDuration * 12) - loanAmount);
}, [monthlyPayment]);
(() => {
// Fetch all the forms we want to apply custom Bootstrap validation styles to
const forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated')
}, false)
})
})()
return (
<div className="widget">
<h4 className="mb-0">Loan Calculator</h4>
<h4>Loan Calculator</h4>
<form onSubmit={(event) => event.preventDefault()}>
<FormInputGroup text="Loan Amount $" placeholder="" value={loanAmount} onInput={(event) => setLoanAmount(event.target.value)}/>
<FormInputGroup text="Interest Rate %" placeholder="" value={interestRate} onInput={(event) => setInterestRate(event.target.value)}/>
<FormInputGroup text="Loan Duration in Years" placeholder="" value={loanDuration} onInput={(event) => setLoanDuration(event.target.value)}/>
<form className="needs-validation" onSubmit={calculateMonthlyPayment} noValidate>
<div className="row">
<div className="col-6">
<div className="input-group">
<label className="input-group-text">Loan Amount $</label>
<input type="number" className="form-control" placeholder="" min={1000} step=".01" value={loanAmount} onChange={(event) => setLoanAmount(event.target.value)} required/>
<div className="invalid-feedback">
Please enter a valid loan amount
<br/>
Loan amount must be of at least $1,000
</div>
</div>
<div className="input-group mt-3">
<label className="input-group-text">Interest Rate %</label>
<input type="number" className="form-control" placeholder="" min={5} step=".001" value={interestRate} onChange={(event) => setInterestRate(event.target.value)} required/>
<div className="invalid-feedback">
Please enter a valid interest rate
<br/>
Interest rate must be of at least 5.0%
</div>
</div>
<div className="input-group mt-3">
<label className="input-group-text">Loan Duration in Years</label>
<input type="number" className="form-control" placeholder="" min={2} value={loanDuration} onChange={(event) => setLoanDuration(event.target.value)} required/>
<div className="invalid-feedback">
Please enter a valid loan duration in years
<br/>
Loan duration cannot be less than 2 years
</div>
</div>
</div>
<h4 className="mt-4 alert alert-info fw-bold">
<div className="col-6">
<h4 className="alert alert-info h-100 fw-bold">
Monthly Payment: ${monthlyPayment.toFixed(2)}
<h5 className="mt-4">Principal Paid: ${loanAmount}</h5>
<h5>Interest Paid: ${interestPaid.toFixed(2)}</h5>
</h4>
<button type="submit" className="btn btn-primary btn-lg w-100 mt-3 center" onClick={calculateMonthlyPayment}>Calculate</button>
</div>
</div>
<button type="submit" className="btn btn-primary btn-lg w-100 mt-3 center">Calculate</button>
</form>
</div>
)

View file

@ -129,16 +129,6 @@ const Settings = () => {
})
})()
// toggle between light mode and dark mode
/*const toggleDarkMode = () => {
if (document.documentElement.getAttribute('data-bs-theme') === 'dark') {
document.documentElement.setAttribute('data-bs-theme','light')
}
else {
document.documentElement.setAttribute('data-bs-theme','dark')
}
}*/
return (
<>
<div className="container overflow-auto">
@ -161,18 +151,18 @@ const Settings = () => {
<div className="row mb-3">
<label htmlFor="newFirstName" className="col-2 col-form-label">New First Name</label>
<div className="col-4">
<input type="text" className="form-control" id="newFirstName" placeholder="Please enter a new first name" value={firstName} onChange={(event) => setFirstName(event.target.value)} required/>
<input type="text" className="form-control" id="newFirstName" placeholder="Please enter a new first name" pattern="\S(.*\S)?" value={firstName} onChange={(event) => setFirstName(event.target.value)} required/>
<div className="invalid-feedback">
Please enter a new first name
Please enter a valid new first name
</div>
</div>
</div>
<div className="row mb-3">
<label htmlFor="newLastName" className="col-2 col-form-label">New Last Name</label>
<div className="col-4">
<input type="text" className="form-control" id="newLastName" placeholder="Please enter a new last name" value={lastName} onChange={(event) => setLastName(event.target.value)} required />
<input type="text" className="form-control" id="newLastName" placeholder="Please enter a new last name" pattern="\S(.*\S)?" value={lastName} onChange={(event) => setLastName(event.target.value)} required/>
<div className="invalid-feedback">
Please enter a new last name
Please enter a valid new last name
</div>
</div>
</div>
@ -187,7 +177,7 @@ const Settings = () => {
<div className="row mb-3">
<label htmlFor="currentPassword" className="col-2 col-form-label">Current Password</label>
<div className="col-4">
<input type="password" className="form-control" id="currentPassword" placeholder="Please enter your current password" minLength="8" value={currentPassword} onChange={(event) => setCurrentPassword(event.target.value)} required />
<input type="password" className="form-control" id="currentPassword" placeholder="Please enter your current password" pattern="\S(.*\S)?" minLength="8" value={currentPassword} onChange={(event) => setCurrentPassword(event.target.value)} required/>
<div className="invalid-feedback">
Please enter your current password
</div>
@ -196,11 +186,13 @@ const Settings = () => {
<div className="row mb-3">
<label htmlFor="newPassword" className="col-2 col-form-label">New Password</label>
<div className="col-4">
<input type="password" className="form-control" id="newPassword" placeholder="Please enter a new password" minLength="8" value={newPassword} onChange={(event) => setNewPassword(event.target.value)} required />
<input type="password" className="form-control" id="newPassword" placeholder="Please enter a new password" pattern="\S(.*\S)?" minLength="8" value={newPassword} onChange={(event) => setNewPassword(event.target.value)} required/>
<div className="invalid-feedback">
Please enter a new password
Please enter a valid new password
<br/>
Your new password must be at least 8 characters long
<br/>
It cannot have whitespace at the start or end of it
</div>
</div>
</div>
@ -210,13 +202,6 @@ const Settings = () => {
</div>
</form>
{/*<h4 className="mb-4">Dark Mode</h4>
<div className="form-check form-switch mb-5">
<input className="form-check-input" type="checkbox" id="darkModeCheckbox" onClick={toggleDarkMode}/>
<label className="form-check-label" htmlFor="darkModeCheckbox">Enable Dark Mode</label>
</div>*/}
<h4 className="mb-4">Account Settings</h4>
<h5 className="mb-4">Delete Your Account</h5>
@ -224,7 +209,7 @@ const Settings = () => {
<div className="row mb-3">
<label htmlFor="deleteAccount" className="col-2 col-form-label">Current Password</label>
<div className="col-4">
<input type="password" className="form-control" id="deleteAccount" placeholder="Please enter your current password" minLength="8" value={deleteAccount} onChange={(event) => setDeleteAccount(event.target.value)} required />
<input type="password" className="form-control" id="deleteAccount" placeholder="Please enter your current password" pattern="\S(.*\S)?" minLength="8" value={deleteAccount} onChange={(event) => setDeleteAccount(event.target.value)} required/>
<div className="invalid-feedback">
Please enter your current password in order to delete your account
</div>