mirror of
https://github.com/gabehf/BudgetBuddy.git
synced 2026-03-14 09:46:11 -07:00
Merge branch 'main' of https://github.com/jacobmveber-01839764/BudgetBuddy
This commit is contained in:
commit
cc3bc06e93
3 changed files with 156 additions and 99 deletions
|
|
@ -123,76 +123,98 @@ const AddExpenseForm = (props) => {
|
||||||
setCost(event.target.value)
|
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 (
|
return (
|
||||||
<div className='widget'>
|
<div className='widget'>
|
||||||
<h4>Add Transaction</h4>
|
<h4>Add Transaction</h4>
|
||||||
<div style={{height: "85%"}} className='d-flex flex-column justify-content-between'>
|
<form className="needs-validation" onSubmit={onSubmit} noValidate>
|
||||||
<div className='row'>
|
<div style={{height: "85%"}} className='d-flex flex-column justify-content-between'>
|
||||||
<div className='col'>
|
<div className='row'>
|
||||||
<label htmlFor='cost'>Cost</label>
|
<div className='col'>
|
||||||
<input
|
<label htmlFor='cost'>Cost</label>
|
||||||
required='required'
|
<input
|
||||||
type='number'
|
required='required'
|
||||||
className='form-control'
|
type='number'
|
||||||
id='cost'
|
className='form-control'
|
||||||
min="0.00"
|
id='cost'
|
||||||
step=".01"
|
min="0.00"
|
||||||
value={cost}
|
step=".01"
|
||||||
onChange={(event) => setCost(event.target.value)}
|
value={cost}
|
||||||
/>
|
onChange={(event) => setCost(event.target.value)}
|
||||||
</div>
|
/>
|
||||||
<div className='col'>
|
<div className="invalid-feedback">
|
||||||
<label htmlFor='category-select'>Category</label>
|
Please enter a valid amount
|
||||||
<select className="form-select" id='category-select'
|
</div>
|
||||||
value={category}
|
</div>
|
||||||
onChange={(event) => setCategory(event.target.value)}>
|
<div className='col'>
|
||||||
|
<label htmlFor='category-select'>Category</label>
|
||||||
|
<select className="form-select" id='category-select'
|
||||||
|
value={category}
|
||||||
|
onChange={(event) => setCategory(event.target.value)}>
|
||||||
|
|
||||||
{categoryList.map((category) => (
|
{categoryList.map((category) => (
|
||||||
<option key={category} value={category}>
|
<option key={category} value={category}>
|
||||||
{category}
|
{category}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='row'>
|
||||||
|
<div className='btn-group mt-2' role="group">
|
||||||
|
<button className='btn btn-outline-success m-right' value={1} onClick={quickSet}>
|
||||||
|
$1
|
||||||
|
</button>
|
||||||
|
<button className='btn btn-outline-success m-right' value={5} onClick={quickSet}>
|
||||||
|
$5
|
||||||
|
</button>
|
||||||
|
<button className='btn btn-outline-success m-right' value={10} onClick={quickSet}>
|
||||||
|
$10
|
||||||
|
</button>
|
||||||
|
<button className='btn btn-outline-success m-right' value={15} onClick={quickSet}>
|
||||||
|
$15
|
||||||
|
</button>
|
||||||
|
<button className='btn btn-outline-success m-right' value={20} onClick={quickSet}>
|
||||||
|
$20
|
||||||
|
</button>
|
||||||
|
<button className='btn btn-outline-success m-right' value={50} onClick={quickSet}>
|
||||||
|
$50
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='row'>
|
||||||
|
<div className='col-sm'>
|
||||||
|
<button className='btn btn-dark m-right mt-2' onClick={toggleTransactionType}>
|
||||||
|
{transactionType.toUpperCase()}
|
||||||
|
</button>
|
||||||
|
<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}>
|
||||||
|
Add New Category
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
<div className='row'>
|
|
||||||
<div className='btn-group mt-2' role="group">
|
|
||||||
<button className='btn btn-outline-success m-right' value={1} onClick={quickSet}>
|
|
||||||
$1
|
|
||||||
</button>
|
|
||||||
<button className='btn btn-outline-success m-right' value={5} onClick={quickSet}>
|
|
||||||
$5
|
|
||||||
</button>
|
|
||||||
<button className='btn btn-outline-success m-right' value={10} onClick={quickSet}>
|
|
||||||
$10
|
|
||||||
</button>
|
|
||||||
<button className='btn btn-outline-success m-right' value={15} onClick={quickSet}>
|
|
||||||
$15
|
|
||||||
</button>
|
|
||||||
<button className='btn btn-outline-success m-right' value={20} onClick={quickSet}>
|
|
||||||
$20
|
|
||||||
</button>
|
|
||||||
<button className='btn btn-outline-success m-right' value={50} onClick={quickSet}>
|
|
||||||
$50
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='row'>
|
|
||||||
<div className='col-sm'>
|
|
||||||
<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'>
|
|
||||||
Add Transaction
|
|
||||||
</button>
|
|
||||||
<button className='btn btn-primary mt-2' onClick={handleAddCategory}>
|
|
||||||
Add New Category
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ const LoanCalculator = () => {
|
||||||
const [monthlyPayment, setMonthlyPayment] = useState(0);
|
const [monthlyPayment, setMonthlyPayment] = useState(0);
|
||||||
const [interestPaid, setInterestPaid] = useState(0);
|
const [interestPaid, setInterestPaid] = useState(0);
|
||||||
|
|
||||||
const calculateMonthlyPayment = () => {
|
const calculateMonthlyPayment = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
const percentageToDecimal = (percent) => {
|
const percentageToDecimal = (percent) => {
|
||||||
return percent / 12 / 100;
|
return percent / 12 / 100;
|
||||||
}
|
}
|
||||||
|
|
@ -24,21 +26,69 @@ const LoanCalculator = () => {
|
||||||
setInterestPaid(monthlyPayment * (loanDuration * 12) - loanAmount);
|
setInterestPaid(monthlyPayment * (loanDuration * 12) - loanAmount);
|
||||||
}, [monthlyPayment]);
|
}, [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 (
|
return (
|
||||||
<div className="widget">
|
<div className="widget">
|
||||||
<h4 className="mb-0">Loan Calculator</h4>
|
<h4>Loan Calculator</h4>
|
||||||
|
|
||||||
<form onSubmit={(event) => event.preventDefault()}>
|
<form className="needs-validation" onSubmit={calculateMonthlyPayment} noValidate>
|
||||||
<FormInputGroup text="Loan Amount $" placeholder="" value={loanAmount} onInput={(event) => setLoanAmount(event.target.value)}/>
|
<div className="row">
|
||||||
<FormInputGroup text="Interest Rate %" placeholder="" value={interestRate} onInput={(event) => setInterestRate(event.target.value)}/>
|
<div className="col-6">
|
||||||
<FormInputGroup text="Loan Duration in Years" placeholder="" value={loanDuration} onInput={(event) => setLoanDuration(event.target.value)}/>
|
<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="alert alert-info fw-bold">
|
<div className="col-6">
|
||||||
Monthly Payment: ${monthlyPayment.toFixed(2)}
|
<h4 className="alert alert-info h-100 fw-bold">
|
||||||
<h5 className="mt-4">Principal Paid: ${loanAmount}</h5>
|
Monthly Payment: ${monthlyPayment.toFixed(2)}
|
||||||
<h5>Interest Paid: ${interestPaid.toFixed(2)}</h5>
|
<h5 className="mt-4">Principal Paid: ${loanAmount}</h5>
|
||||||
</h4>
|
<h5>Interest Paid: ${interestPaid.toFixed(2)}</h5>
|
||||||
<button type="submit" className="btn btn-primary btn-lg w-100 mt-3 center" onClick={calculateMonthlyPayment}>Calculate</button>
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" className="btn btn-primary btn-lg w-100 mt-3 center">Calculate</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container overflow-auto">
|
<div className="container overflow-auto">
|
||||||
|
|
@ -161,18 +151,18 @@ const Settings = () => {
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
<label htmlFor="newFirstName" className="col-2 col-form-label">New First Name</label>
|
<label htmlFor="newFirstName" className="col-2 col-form-label">New First Name</label>
|
||||||
<div className="col-4">
|
<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">
|
<div className="invalid-feedback">
|
||||||
Please enter a new first name
|
Please enter a valid new first name
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
<label htmlFor="newLastName" className="col-2 col-form-label">New Last Name</label>
|
<label htmlFor="newLastName" className="col-2 col-form-label">New Last Name</label>
|
||||||
<div className="col-4">
|
<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">
|
<div className="invalid-feedback">
|
||||||
Please enter a new last name
|
Please enter a valid new last name
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -187,7 +177,7 @@ const Settings = () => {
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
<label htmlFor="currentPassword" className="col-2 col-form-label">Current Password</label>
|
<label htmlFor="currentPassword" className="col-2 col-form-label">Current Password</label>
|
||||||
<div className="col-4">
|
<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">
|
<div className="invalid-feedback">
|
||||||
Please enter your current password
|
Please enter your current password
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -196,11 +186,13 @@ const Settings = () => {
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
<label htmlFor="newPassword" className="col-2 col-form-label">New Password</label>
|
<label htmlFor="newPassword" className="col-2 col-form-label">New Password</label>
|
||||||
<div className="col-4">
|
<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">
|
<div className="invalid-feedback">
|
||||||
Please enter a new password
|
Please enter a valid new password
|
||||||
<br/>
|
<br/>
|
||||||
Your new password must be at least 8 characters long
|
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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -210,13 +202,6 @@ const Settings = () => {
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</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>
|
<h4 className="mb-4">Account Settings</h4>
|
||||||
|
|
||||||
<h5 className="mb-4">Delete Your Account</h5>
|
<h5 className="mb-4">Delete Your Account</h5>
|
||||||
|
|
@ -224,7 +209,7 @@ const Settings = () => {
|
||||||
<div className="row mb-3">
|
<div className="row mb-3">
|
||||||
<label htmlFor="deleteAccount" className="col-2 col-form-label">Current Password</label>
|
<label htmlFor="deleteAccount" className="col-2 col-form-label">Current Password</label>
|
||||||
<div className="col-4">
|
<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">
|
<div className="invalid-feedback">
|
||||||
Please enter your current password in order to delete your account
|
Please enter your current password in order to delete your account
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue