Code
unknown
plain_text
2 years ago
62 kB
25
Indexable
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Finance Tracker</title>
<link href="static/assets/css/feather-icons.css" rel="stylesheet">
<link href="static/assets/css/style.css" rel="stylesheet">
<style>
/* Import Nexa Bold font from an online source */
@import url('https://fonts.googleapis.com/css2?family=Nexa:wght@700&display=swap');
@import url('https://cdn-uicons.flaticon.com/uicons-regular-rounded/css/uicons-regular-rounded.css');
</style>
<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.27.3/dist/apexcharts.min.js"></script>
</head>
<body>
<div id="myModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h1>Edit Row</h1>
<div class="modal-body">
<div class="input-group">
<label for="nameInput">Name</label>
<input type="text" id="nameInput" >
</div>
<div class="input-group">
<label for="incomeInput">Income</label>
<input type="text" id="incomeInput" >
</div>
<div class="input-group">
<label for="accountInput">Bank Account</label>
<input type="text" id="accountInput" >
</div>
<div class="input-group">
<label for="sourceInput">Income Source</label>
<input type="text" id="sourceInput" >
</div>
<div class="input-group">
<label for="dateInput">Date</label>
<input type="text" id="dateInput">
</div>
</div>
<div id="addModal" style="display: none; position: absolute; top: 100%; left: 0; width: 100%;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalTitle">Add Expense</h5>
<span class="close">×</span>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="nameInput">Name:</label>
<input type="text" class="form-control" id="newSourceInput">
</div>
<div class="form-group">
<label for="descriptionInput">Description:</label>
<input type="text" class="form-control" id="descriptionInput">
</div>
</form>
</div>
<div class="modal-footer">
<div class="button-container">
<button type="button" class="btn btn-secondary close">Close</button>
<button type="button" class="btn btn-primary" id = "save-btn">Save</button>
</div>
</div>
</div>
</div>
<button id="addIncomeButton" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
</svg>Add New Income Source</button>
<button id="addExpenseButton" style="display: none;"> <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
</svg>Add New Expense Source</button>
</div>
</div>
<div class="container">
<h1 style="font-size: 38px; margin-bottom: 0;">Finance Tracker</h1>
<div class="outline-box">
<i class="fi fi-rr-chart-line-up"></i>
<span class="overview-text">Overview</span>
<div class="card-container">
<div class="card"></div>
<div class="card"></div>
<div class="chart-container">
<canvas id="line-chart"></canvas>
</div>
</div>
</div>
<div class="outline-box">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-wallet" viewBox="0 0 16 16">
<path d="M0 3a2 2 0 0 1 2-2h13.5a.5.5 0 0 1 0 1H15v2a1 1 0 0 1 1 1v8.5a1.5 1.5 0 0 1-1.5 1.5h-12A2.5 2.5 0 0 1 0 12.5V3zm1 1.732V12.5A1.5 1.5 0 0 0 2.5 14h12a.5.5 0 0 0 .5-.5V5H2a1.99 1.99 0 0 1-1-.268zM1 3a1 1 0 0 0 1 1h12V2H2a1 1 0 0 0-1 1z"/>
</svg>
<span class="overview-text">Finances</span>
<!-- Buttons inside the Finances outline box -->
<div class="tab_box">
<button class="tab_btn">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-plus-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
</svg>
<span class="text">Today</span>
</button>
<button class="tab_btn">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-dash-circle" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z"/>
</svg>
<span class="text">Today</span>
</button>
<button class="tab_btn">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-arrow-up-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-7.5 3.5a.5.5 0 0 1-1 0V5.793L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11.5z"/>
</svg>
<span class="text">Income</span>
</button>
<button class="tab_btn">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-arrow-down-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.5 4.5a.5.5 0 0 0-1 0v5.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V4.5z"/>
</svg>
<span class="text">Expenses</span>
</button>
<button class="tab_btn">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
</svg>
<span class="text">Calendar</span>
</button>
<div class="line"></div>
</div>
<!-- Content divs inside the Finances outline box -->
<div class="content-box">
<div class="content">
<div class="horizontal-line"></div>
<table>
<thead>
<tr>
<th>
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" fill="currentColor" class="bi bi-type" viewBox="0 0 17 17">
<path d="m2.244 13.081.943-2.803H6.66l.944 2.803H8.86L5.54 3.75H4.322L1 13.081h1.244zm2.7-7.923L6.34 9.314H3.51l1.4-4.156h.034zm9.146 7.027h.035v.896h1.128V8.125c0-1.51-1.114-2.345-2.646-2.345-1.736 0-2.59.916-2.666 2.174h1.108c.068-.718.595-1.19 1.517-1.19.971 0 1.518.52 1.518 1.464v.731H12.19c-1.647.007-2.522.8-2.522 2.058 0 1.319.957 2.18 2.345 2.18 1.06 0 1.716-.43 2.078-1.011zm-1.763.035c-.752 0-1.456-.397-1.456-1.244 0-.65.424-1.115 1.408-1.115h1.805v.834c0 .896-.752 1.525-1.757 1.525z"/>
</svg>
<span class="text">Name</span></th>
<th>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cash" viewBox="0 0 16 16">
<path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/>
<path d="M0 4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V4zm3 0a2 2 0 0 1-2 2v4a2 2 0 0 1 2 2h10a2 2 0 0 1 2-2V6a2 2 0 0 1-2-2H3z"/>
</svg><span class="text">Income</span></th>
<th><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-bank2" viewBox="0 0 16 16">
<path d="M8.277.084a.5.5 0 0 0-.554 0l-7.5 5A.5.5 0 0 0 .5 6h1.875v7H1.5a.5.5 0 0 0 0 1h13a.5.5 0 1 0 0-1h-.875V6H15.5a.5.5 0 0 0 .277-.916l-7.5-5zM12.375 6v7h-1.25V6h1.25zm-2.5 0v7h-1.25V6h1.25zm-2.5 0v7h-1.25V6h1.25zm-2.5 0v7h-1.25V6h1.25zM8 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM.5 15a.5.5 0 0 0 0 1h15a.5.5 0 1 0 0-1H.5z"/>
</svg> <span class="text">Bank Account</span></th>
<th>
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-arrow-up-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-7.5 3.5a.5.5 0 0 1-1 0V5.793L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11.5z"/>
</svg><span class="text">Income Source</span> </th>
<th class="no-right-border">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
</svg><span class="text">Date</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" class="input-box" data-column="name"></td>
<td><input type="number" class="input-box" data-column="income"></td>
<td><input type="text" class="input-box" data-column="bank_account"></td>
<td><select id ="dropdown_table" data-column="income_source"></select></td>
<td class="no-right-border"><input type="text" class="input-box" data-column="date"></td>
</tr>
</tbody>
</table>
<div class="horizontal-line"></div>
<div class = "row-add">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
</svg>
<span>New</span>
</div>
<div class="horizontal-line"></div>
</div>
<div class="content">
<div class="horizontal-line"></div>
<table id ="expense-table">
<thead>
<tr>
<th>
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" fill="currentColor" class="bi bi-type" viewBox="0 0 17 17">
<path d="m2.244 13.081.943-2.803H6.66l.944 2.803H8.86L5.54 3.75H4.322L1 13.081h1.244zm2.7-7.923L6.34 9.314H3.51l1.4-4.156h.034zm9.146 7.027h.035v.896h1.128V8.125c0-1.51-1.114-2.345-2.646-2.345-1.736 0-2.59.916-2.666 2.174h1.108c.068-.718.595-1.19 1.517-1.19.971 0 1.518.52 1.518 1.464v.731H12.19c-1.647.007-2.522.8-2.522 2.058 0 1.319.957 2.18 2.345 2.18 1.06 0 1.716-.43 2.078-1.011zm-1.763.035c-.752 0-1.456-.397-1.456-1.244 0-.65.424-1.115 1.408-1.115h1.805v.834c0 .896-.752 1.525-1.757 1.525z"/>
</svg>
<span class="text">Name</span></th>
<th>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cash" viewBox="0 0 16 16">
<path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/>
<path d="M0 4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V4zm3 0a2 2 0 0 1-2 2v4a2 2 0 0 1 2 2h10a2 2 0 0 1 2-2V6a2 2 0 0 1-2-2H3z"/>
</svg><span class="text">Expense</span></th>
<th><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-bank2" viewBox="0 0 16 16">
<path d="M8.277.084a.5.5 0 0 0-.554 0l-7.5 5A.5.5 0 0 0 .5 6h1.875v7H1.5a.5.5 0 0 0 0 1h13a.5.5 0 1 0 0-1h-.875V6H15.5a.5.5 0 0 0 .277-.916l-7.5-5zM12.375 6v7h-1.25V6h1.25zm-2.5 0v7h-1.25V6h1.25zm-2.5 0v7h-1.25V6h1.25zm-2.5 0v7h-1.25V6h1.25zM8 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2zM.5 15a.5.5 0 0 0 0 1h15a.5.5 0 1 0 0-1H.5z"/>
</svg> <span class="text">Bank Account</span></th>
<th>
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-arrow-down-circle" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.5 4.5a.5.5 0 0 0-1 0v5.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V4.5z"/>
</svg>
<span class="text">Expense Source</span> </th>
<th class="no-right-border">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
</svg><span class="text">Date</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" class="input-box" data-column="name"></td>
<td><input type="text" class="input-box" data-column="income"></td>
<td><input type="text" class="input-box" data-column="bank_account"></td>
<td><select id ="expense_dropdown" data-column="income_source"></select></td>
<td class="no-right-border"><input type="text" class="input-box" data-column="date"></td>
</tr>
</tbody>
</table>
<div class="horizontal-line"></div>
<div class="row-add-expense">
<button class="expense-btn"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
</svg>New</button>
</div>
<div class="horizontal-line"></div>
</div>
<div class="content">
</div>
<div class="content">
</div>
<div class="content">
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="static/assets/js/script.js"></script>
<script src="static/assets/js/modal.js"></script>
<script src="static/assets/js/expense_modal.js"></script>
<script src="https://unpkg.com/@themesberg/flowbite@1.2.0/dist/flowbite.bundle.js"></script>
</body>
</html>
/* style.css (Your main CSS file) */
body {
padding: 0px;
margin-top: 20px;
margin-left: 30px;
background-color: #121212;
color: white;
font-family: "Nexa Bold", sans-serif;
font-weight: bold;
}
.container {
margin: 0 auto;
padding: 50px;
display: flex;
flex-direction: column;
}
.overview-text {
font-family: "Nexa Bold", sans-serif;
font-size: 18px; /* Adjust the font size as needed */
margin-left: 12px;
}
.outline-box {
margin-top: 60px;
border: 0.5px solid #6262627e;
background-color: transparent;
padding: 10px;
border-radius: 0.5px;
}
.small-outline-box {
width: 500px;
height: 400px;
margin-top: 60px;
border: 0.5px solid #6262627e;
background-color: transparent;
padding: 10px;
border-radius: 0.5px;
}
.card-container {
display: flex;
padding-bottom: 20px;
border-radius: 0px;
margin-top: 30px;
margin-left: 10px;
}
.card {
width: 200px;
height: 300px;
background: #242323;
margin-left: 20px;
}
.chart-container {
margin-left: 15px;
flex: 1;
height: 450px;
}
::-webkit-scrollbar {
width: 10px;
background-color: #30373d;
}
::-webkit-scrollbar-thumb {
background-color: #555;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background-color: #555;
}
.tab_box{
width: 100%;
display:flex;
align-items: left;
position: relative;
}
.tab_btn{
margin-top: 20px;
margin-bottom: 40px;
margin-right: 10px;
font-size: 20px;
background: none;
border: none;
color: white;
cursor: pointer;
}
.line{
position: absolute;
top: 50px;
left:0;
width: 90px;
height: 4px;
background-color: #30373d;
border-radius: 10px;
transition: all .3s ease-in-out;
}
.text{
margin-left: 0px;
font-size: 18px;
}
table {
width: 80%;
}
table th .text {
font-size: 16px;
font-weight: normal;
color: #ffffff;
}
table th svg {
margin-right: 5px; /* Add some right margin between the icon and the text */
}
th, td {
text-align: left;
font-size: 16px;
font-weight: normal;
padding: 4px;
border-right: 1px solid rgba(255, 255, 255, 0.315);
}
/* Styling for table header */
th {
background-color: transparent;
}
th.no-right-border {
border-right: none;
}
.input-box {
border: none; /* Remove the default border */
outline: none; /* Remove the default outline */
font-size: 14px;
background: transparent; /* Set the background to transparent */
color: #fff; /* Text color for input boxes */
box-shadow: none; /* Remove the box-shadow */
}
tr td:last-child {
border-right: none;
}
tr:hover {
background-color: #4e4e4e15; /* Change to the desired color when hovering */
}
.horizontal-line {
width: 100%; /* Set the width of the line to fill the entire container */
height: 0.5px; /* Set the height of the line */
background-color: rgba(255, 255, 255, 0.219); /* Change the color of the line (you can use any valid CSS color) */
}
.row-add {
display: flex; /* Adding flex display to align items horizontally */
align-items: center; /* Aligning items vertically in the center */
font-size: 16px; /* Adjust this value to change the font size */
font-weight: normal;
padding: 4px;
cursor: pointer;
color: rgba(99, 99, 99, 0.589);
}
.row-add:hover{
color: white;
}
/* Styling for the SVG icon */
.row-add svg {
margin-right: 10px; /* Adjust this value to add space between the icon and text */
}
.modal {
display: none;
position: fixed;
z-index: 1;
right: 0; /* Position from the right side */
top: 0;
width: 40%; /* Adjust the width as needed */
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
transition: right 0.3s; /* Add a smooth transition effect */
}
.modal-content {
background-color: #242323;
height: 100%;
border-radius: 2px;
padding: 16px;
}
.modal-body {
margin-top: 5px;
display: flex; /* Create a flex container */
flex-direction: column; /* Arrange elements vertically */
}
.input-group {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.input-group label {
min-width: 120px; /* Adjust this width as needed */
margin-left: 20px;
font-size: 16px;
font-weight: normal;
}
.modal-body input {
padding-left: 20px;
border: none; /* Remove the default border */
outline: none; /* Remove the default outline */
background: transparent; /* Set the background to transparent */
color: #fff; /* Text color for input boxes */
box-shadow: none; /* Remove the box-shadow */
font-size: 16px;
align-items: left;
flex: 1;
}
.close {
color: #aaa;
float: right;
font-size: 24px;
font-weight: bold;
cursor: pointer;
}
.modal-content h1 {
/* Set the font size */
font-weight: bold; /* Make the text bold */
color: #fff; /* Set the text color to white */
margin-top: 40px; /* Remove the default top margin for <h1> */
margin-bottom: 40px; /* Adjust the bottom margin as needed */
}
.expense-btn {
background-color: transparent;
border: none;
outline: none;
cursor: pointer;
align-items: center; /* Aligning items vertically in the center */
font-size: 16px; /* Adjust this value to change the font size */
font-weight: normal;
padding: 4px;
align-items: center;
font-size: 16px;
color: rgba(99, 99, 99, 0.589);
}
/* Add padding to separate the icon from text */
.expense-btn svg {
margin-right: 5px;
color: rgba(99, 99, 99, 0.589);
}
/* Hover effect on the button and the SVG */
.expense-btn:hover
{
padding: 4px;
color:white;
}
.modal-content button {
margin-top: 40px;
margin-left: 20px;
margin-bottom: 10px;
background-color: #0d71bd;
border-radius: 3px;
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
}
/* Additional style for the buttons */
.modal-content button:hover {
background-color: #008df9;
}
.modal-content button svg {
margin-right: 5px;
vertical-align: middle; /* Added to vertically align the icon with the text */
}
#addModal {
display: none; /* Hide the modal by default */
background-color: #222222;
max-width: 400px;
max-height: 200px;
margin-left: 36px;
border-radius: 3px;
}
#addModal .modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background-color: #121316;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
/* Form labels */
#addModal label {
display: block;
font-size: 0.9rem;
font-weight: 500;
color: #333;
}
#addModal .modal-content{
padding: 0;
}
/* Form inputs */
#addModal input[type="text"] {
width: 100%;
border-radius: 4px;
}
#addModal #newSourceInput.form-control {
width: 90%;
padding: 0;
font-size: 12px;
min-height: 36px;
background-color: #1d1d1d;
color: white;
}
#addModal #descriptionInput.form-control {
padding: 0px;
width: 90%;
font-size: 12px;
min-height: 60px ;
background-color: #1d1d1d;
color: white;
}
/* Modal header title */
#addModal .modal-title {
margin: 0;
font-size: 14px;
font-weight: normal;
}
/* Modal body */
#addModal .modal-body {
padding-left: 1rem;
padding-top: 1rem;
padding-right: 1rem;
margin: 0;
background-color: #121316;
}
/* Form group */
#addModal .form-group {
margin-bottom: 1rem;
}
/* Form labels */
#addModal label {
margin-top: 20px;
margin-bottom: 10px;
display: block;
font-size: 0.9rem;
font-weight: 500;
color: #ffffff;
}
/* Form inputs */
#addModal input[type="text"] {
width: 100%;
padding: 0.5rem 1rem;
border-radius: 4px;
}
/* Close button */
#addModal .close {
font-size: 1.2rem;
color: #333;
cursor: pointer;
}
#addModal .modal-footer {
display: flex;
justify-content: flex-end;
align-items: center; /* Vertically align the buttons in the center */
background-color: #121316;
max-height: 50px;
overflow: hidden; /* Hide the overflowing content */
}
.button-container {
display: flex;
flex-wrap: nowrap; /* Prevent button wrapping */
}
#addModal .btn {
margin-bottom: 30px;/* Add some space between buttons */
padding: 5px 10px; /* Adjust padding to make buttons smaller */
max-width: 100px; /* Limit the width of the buttons */
white-space: nowrap; /* Prevent button text wrapping */
}
#addModal .btn-primary {
margin-right: 50px;
background-color: #0d71bd;
color: white;
border: none;
font-size: 12px;
cursor: pointer;
}
#addModal .btn-primary:hover {
background-color: #008df9; /* Change the background color on hover */
}
#addModal .btn-secondary {
font-weight: normal;
background-color: transparent;
font-size: 12px;
color: #ffffff67;
border: none;
cursor: pointer;
}
#addModal .btn-secondary:hover {
color: white; /* Change the background color on hover */
}
from flask import Flask, render_template, request, jsonify
from flask import Blueprint
import pyodbc
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/get_data', methods=['GET'])
def get_data():
try:
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor = conn.cursor()
cursor.execute("SELECT * FROM INCOME")
data = cursor.fetchall()
columns = ['Name', 'Income', 'BankAccount', 'IncomeSource', 'Date']
rows = [{col: row[i] for i, col in enumerate(columns)} for row in data]
return jsonify(rows)
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/add_row', methods=['POST'])
def add_row():
try:
data = request.json
name = data.get('name')
income = data.get('income')
bank_account = data.get('bank_account')
income_source = data.get('income_source')
date = data.get('date')
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor = conn.cursor()
cursor.execute("INSERT INTO INCOME (Name, Income, BankAccount, IncomeSource, Date,user_name) "
"VALUES (?, ?, ?, ?, ?,'Test')", (name, income, bank_account, income_source, date))
conn.commit()
return jsonify({"message": "Row added successfully!"})
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/get_expense_data', methods=['GET'])
def get_expense_data():
try:
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor.execute("SELECT * FROM EXPENSE") # Assuming the "EXPENSE" table contains the data for the Expense table
data = cursor.fetchall()
columns = ['Name', 'Expense', 'BankAccount', 'ExpenseSource', 'Date'] # Adjust the column names as per your actual table
rows = [{col: row[i] for i, col in enumerate(columns)} for row in data]
return jsonify(rows)
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/add_expense_row', methods=['POST'])
def add_expense_row():
try:
data = request.json
name = data.get('name')
expense = data.get('expense')
bank_account = data.get('bank_account')
expense_source = data.get('expense_source') # Assuming the column name is different in the Expense table
date = data.get('date')
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor.execute("INSERT INTO EXPENSE (Name, Expense, BankAccount, ExpenseSource, Date,user_name) "
"VALUES (?, ?, ?, ?, ?,'Test')", (name, expense, bank_account, expense_source, date)) # Adjust the column names as per your actual table
conn.commit()
return jsonify({"message": "Row added to the Expense table successfully!"})
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/add_expense_source', methods=['POST'])
def add_expense_source():
try:
data = request.json
new_source_name = data.get('newSourceName')
description = data.get('description')
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor.execute("INSERT INTO ExpenseSources (source_name, description) VALUES (?, ?)", (new_source_name, description))
conn.commit()
return jsonify({"message": "New expense source added successfully!"})
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/add_income_source', methods=['POST'])
def add_income_source():
try:
data = request.json
new_source_name = data.get('newSourceName')
description = data.get('description')
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor.execute("INSERT INTO IncomeSources (source_name, description) VALUES (?, ?)", (new_source_name, description))
conn.commit()
return jsonify({"message": "New income source added successfully!"})
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/get_income_sources', methods=['GET'])
def get_income_sources():
try:
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor.execute("SELECT source_name FROM IncomeSources")
income_sources = [row[0] for row in cursor.fetchall()]
return jsonify({"income_sources": income_sources})
except Exception as e:
return jsonify({"error": str(e)})
@app.route('/get_expense_sources', methods=['GET'])
def get_expense_sources():
try:
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=SOHAIL_LAPTOP;DATABASE=FTrackDB;UID=sa;PWD=sohail2004')
cursor = conn.cursor()
cursor.execute("SELECT source_name FROM ExpenseSources")
expense_sources = [row[0] for row in cursor.fetchall()]
return jsonify({"expense_sources": expense_sources}) # Corrected variable name
except Exception as e:
return jsonify({"error": str(e)})
if __name__ == '__main__':
app.run(debug=True, host='192.168.0.107', port=5000)
#app.run(debug=True, host='192.168.1.108', port=5000)
//script 1
document.addEventListener("DOMContentLoaded", function () {
var ctx = document.getElementById("line-chart").getContext('2d');
var options = {
type: "line",
data: {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"],
datasets: [
{
label: 'Sample Series',
data: [35, 40, 35, 50, 49, 60, 70, 91, 110],
fill: true,
borderColor: '#2196f3',
backgroundColor: 'rgba(33, 150, 243, 0.2)',
borderWidth: 2,
pointRadius: 5,
pointBackgroundColor: '#2196f3',
pointBorderColor: '#ffffff',
pointBorderWidth: 2,
}
]
},
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 2, // Set the desired aspect ratio (height/width) for the chart
scales: {
x: {
grid: {
display: true,
drawBorder: true, // Display vertical grid lines at chart borders
drawTicks: false, // Hide the ticks on the X-axis
color: 'rgba(255, 255, 255, 0.1)',
lineWidth: 1,
}
},
y: {
grid: {
display: true,
drawBorder: true, // Display horizontal grid lines at chart borders
drawTicks: false, // Hide the ticks on the Y-axis
color: 'rgba(255, 255, 255, 0.1)',
lineWidth: 1,
}
}
},
plugins: {
legend: {
display: false
}
},
layout: {
padding: {
top: 10,
right: 15,
bottom: 15,
left: 15
}
}
}
};
var chart = new Chart(ctx, options);
// Get all tab buttons and content div
const tabButtons = document.querySelectorAll(".tab_btn");
const contentDivs = document.querySelectorAll(".content");
const line = document.querySelector('.line');
// Function to hide all content divs
function hideContent() {
contentDivs.forEach(function (content) {
content.style.display = "none";
});
}
function showContent(index) {
// Hide all content divs
hideContent();
// Show the selected content div
contentDivs[index].style.display = "block";
}
// Initially hide all content divs except the first one
hideContent();
showContent(0);
// Add click event listener to each tab button
tabButtons.forEach(function (button, index) {
button.addEventListener("click", function () {
// Remove the "active" class from all buttons and content divs
tabButtons.forEach(function (btn) {
btn.classList.remove("active");
});
contentDivs.forEach(function (content) {
content.classList.remove("active");
});
// Add the "active" class to the clicked button and content div
button.classList.add("active");
showContent(index);
const buttonOffsetLeft = button.offsetLeft;
const buttonWidth = button.offsetWidth;
line.style.left = buttonOffsetLeft + "px";
line.style.width = buttonWidth + "px";
});
});
async function createNewRow() {
const table = document.querySelector('table');
const newRow = document.createElement('tr');
const columns = ['name', 'income', 'bank_account', 'income_source', 'date'];
// Fetch income sources and populate the dropdown options
const response = await fetchIncomeSources();
const incomeSources = response.income_sources;
console.log(incomeSources);
const select = document.createElement('select');
select.id = 'dropdown_table';
select.classList.add('input-box');
select.dataset.column = 'income_source'; // Set the column to identify the selected value
// Add an empty option as the default
const emptyOption = document.createElement('option');
emptyOption.value = '';
emptyOption.textContent = 'Select Income Source';
select.appendChild(emptyOption);
// Populate the dropdown with income source options
incomeSources.forEach(incomeSource => {
const option = document.createElement('option');
option.value = incomeSource;
option.textContent = incomeSource;
select.appendChild(option);
});
columns.forEach(column => {
const cell = document.createElement('td');
// Check if it's the income_source column and add the select dropdown
if (column === 'income_source') {
cell.appendChild(select);
} else {
const input = document.createElement('input');
input.type = 'text';
input.classList.add('input-box');
input.dataset.column = column;
cell.appendChild(input);
}
newRow.appendChild(cell);
});
// Add a blur event listener to each input field
columns.forEach(col => {
const input = newRow.querySelector(`[data-column="${col}"]`);
input.addEventListener('blur', function () {
const rowData = {};
let allFieldsFilled = true; // Variable to check if all fields are filled
columns.forEach(col => {
const input = newRow.querySelector(`[data-column="${col}"]`);
rowData[col] = input.value;
if (!input.value) {
allFieldsFilled = false;
}
});
if (allFieldsFilled) {
saveNewRowData(rowData);
} else {
console.log('Please fill all required fields.');
}
});
});
table.querySelector('tbody').appendChild(newRow);
}
// Function to fetch income sources from the server
async function fetchIncomeSources() {
try {
const response = await fetch('/get_income_sources');
const data = await response.json();
if (data && data.income_sources && Array.isArray(data.income_sources)) {
return data.income_sources; // Return the array of income sources
} else {
console.error('Received invalid income sources data from the server.');
return []; // Return an empty array if data format is invalid
}
} catch (error) {
console.error('Error fetching income sources:', error);
return []; // Return an empty array on error
}
}
async function fetchExpenseSources() {
try {
const response = await fetch('/get_expense_sources');
const data = await response.json();
if (data && data.expense_sources && Array.isArray(data.expense_sources)) {
return data.expense_sources; // Return the array of income sources
} else {
console.error('Received invalid expense sources data from the server.');
return []; // Return an empty array if data format is invalid
}
} catch (error) {
console.error('Error fetching expense sources:', error);
return []; // Return an empty array on error
}
}
function fetchAndPopulateExpenseTable() {
fetch('/get_expense_data') // Replace '/get_expense_data' with the appropriate endpoint that retrieves data for the Expense table
.then(response => response.json())
.then(data => {
const table = document.getElementById('expense-table');
const tbody = table.querySelector('tbody');
tbody.innerHTML = ''; // Clear existing rows
data.forEach(rowData => {
const newRow = document.createElement('tr');
const columns = ['Name', 'Expense', 'BankAccount', 'ExpenseSource', 'Date']; // Assuming the column names in the Expense table are different from the Income table
columns.forEach(column => {
const cell = document.createElement('td');
const input = document.createElement('input');
input.type = 'text';
input.classList.add('input-box');
input.dataset.column = column;
input.value = rowData[column]; // Access the data using the column key
input.disabled = true;
cell.appendChild(input);
newRow.appendChild(cell);
});
tbody.appendChild(newRow);
});
})
.catch(error => console.error('Error fetching data for Expense table:', error));
}
// Call this function when the page loads or when switching to the Expense tab
fetchAndPopulateExpenseTable();
function fetchDataAndPopulateTable() {
fetch('/get_data')
.then(response => response.json())
.then(data => {
// Verify that the data is received correctly
console.log(data);
const table = document.querySelector('table');
const tbody = table.querySelector('tbody');
tbody.innerHTML = ''; // Clear existing rows
data.forEach(rowData => {
const newRow = document.createElement('tr');
const columns = ['Name', 'Income', 'BankAccount', 'IncomeSource', 'Date'];
columns.forEach(column => {
const cell = document.createElement('td');
const input = document.createElement('input');
input.type = 'text';
input.classList.add('input-box');
input.dataset.column = column;
input.value = rowData[column];
input.disabled = true;// Access the data using the column key
cell.appendChild(input);
newRow.appendChild(cell);
});
tbody.appendChild(newRow);
});
})
.catch(error => console.error('Error fetching data:', error));
}
function saveNewRowData(rowData) {
console.log("Data to be sent to the server:", rowData);
// Retrieve the selected income source from the dropdown
const incomeSourceDropdown = document.querySelector('select[data-column="income_source"]');
rowData['income_source'] = incomeSourceDropdown.value;
fetch('/add_row', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(rowData)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error saving data:', error));
}
fetchDataAndPopulateTable();
async function createNewExpenseRow() {
const table = document.getElementById('expense-table');
const newRow = document.createElement('tr');
const columns = ['name', 'expense', 'bank_account', 'expense_source', 'date'];
// Fetch expense sources and populate the dropdown options
const expenseSources = await fetchExpenseSources();
console.log(expenseSources);
const select = document.createElement('select');
select.id = 'expense_dropdown';
select.classList.add('input-box');
select.dataset.column = 'expense_source'; // Set the column to identify the selected value
const emptyOption = document.createElement('option');
emptyOption.value = ''; // Set the value of the option to an empty string
emptyOption.textContent = 'Select Expense Source'; // Set the displayed text
select.appendChild(emptyOption);
// Populate the dropdown with expense source options
expenseSources.forEach(expenseSource => {
const option = document.createElement('option');
option.value = expenseSource;
option.textContent = expenseSource;
select.appendChild(option);
});
columns.forEach(column => {
const cell = document.createElement('td');
const input = document.createElement('input');
input.type = 'text';
input.classList.add('input-box');
input.dataset.column = column;
// Check if it's the expense_source column and add the select dropdown
if (column === 'expense_source') {
cell.appendChild(select);
} else {
cell.appendChild(input);
}
newRow.appendChild(cell);
});
// Add a blur event listener to each input field
columns.forEach(col => {
const input = newRow.querySelector(`[data-column="${col}"]`);
input.addEventListener('blur', function () {
const rowData = {};
let allFieldsFilled = true; // Variable to check if all fields are filled
columns.forEach(col => {
const input = newRow.querySelector(`[data-column="${col}"]`);
rowData[col] = input.value;
if (!input.value) {
allFieldsFilled = false;
}
});
// Update the expense_source value in rowData with the selected dropdown option
rowData['expense_source'] = select.value;
if (allFieldsFilled) {
// Save the new expense row data to the database
saveNewExpenseRowData(rowData);
} else {
console.log('Please fill all required fields.');
}
});
});
table.querySelector('tbody').appendChild(newRow);
}
function saveNewExpenseRowData(rowData) {
console.log("Data to be sent to the server:", rowData);
fetch('/add_expense_row', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(rowData)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error saving data:', error));
}
async function fetchIncomeSources() {
try {
const response = await fetch('/get_income_sources');
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching income sources:', error);
return [];
}
}
// Call this function when clicking the "New" button in the Expense section
document.querySelector('.expense-btn').addEventListener('click', function () {
createNewExpenseRow();
});
// Add click event listener to the "New" button
document.querySelector('.row-add').addEventListener('click', function () {
createNewRow();
});
});
//script2
// Get the modal element
const modal = document.getElementById("myModal");
const addModal = document.getElementById("addModal");
const modalTitleElement = document.getElementById("modalTitle");
// Get the first table element
const table = document.querySelector("table");
// Get the second table element
const expenseTable = document.getElementById("expense-table");
// Variable to keep track of the current row index being edited
let currentRowIndex = null;
function addEventListenersForButtons() {
const addExpenseButton = document.getElementById("addExpenseButton");
const addIncomeButton = document.getElementById("addIncomeButton");
addExpenseButton.addEventListener("click", onAddExpenseButtonClick);
addIncomeButton.addEventListener("click", onAddIncomeButtonClick);
}
function removeEventListenersForButtons() {
const addExpenseButton = document.getElementById("addExpenseButton");
const addIncomeButton = document.getElementById("addIncomeButton");
addExpenseButton.removeEventListener("click", onAddExpenseButtonClick);
addIncomeButton.removeEventListener("click", onAddIncomeButtonClick);
}
// Function to handle the click event for adding an expense
function onAddExpenseButtonClick() {
const buttonRect = addExpenseButton.getBoundingClientRect();
addModal.style.display = "block";
addModal.style.position = "absolute";
addModal.style.top = buttonRect.bottom + "px";
modalTitleElement.textContent = "Add Expense Source"; // Change title for expense table
const addCloseBtn = document.querySelector("#addModal .close");
addCloseBtn.addEventListener("click", function () {
addModal.style.display = "none";
addCloseBtn.removeEventListener("click", onAddExpenseButtonClick); // Remove the event listener
window.removeEventListener("click", onCloseButtonClick); // Remove the click event listener for closing the modal
});
// Attach a click event to the window to close the modal when clicked outside
window.addEventListener("click", onCloseButtonClick);
}
// Function to handle the click event for adding an income
function onAddIncomeButtonClick() {
const buttonRect = addIncomeButton.getBoundingClientRect();
addModal.style.display = "block";
addModal.style.position = "absolute";
addModal.style.top = buttonRect.bottom + "px";
modalTitleElement.textContent = "Add Income Source"; // Change title for income table
document.getElementById("nameInput").value = "";
document.getElementById("descriptionInput").value = "";
const addCloseBtn = document.querySelector("#addModal .close");
addCloseBtn.addEventListener("click", function () {
addModal.style.display = "none";
addCloseBtn.removeEventListener("click", onAddIncomeButtonClick); // Remove the event listener
window.removeEventListener("click", onCloseButtonClick); // Remove the click event listener for closing the modal
});
// Attach a click event to the window to close the modal when clicked outside
window.addEventListener("click", onCloseButtonClick);
}
// Function to handle the click event for closing the modal
function onCloseButtonClick(event) {
if (event.target === modal || event.target === addModal) {
modal.style.display = "none";
addModal.style.display = "none";
// When the modal is closed, remove the event listeners
const addCloseBtn = document.querySelector("#addModal .close");
addCloseBtn.removeEventListener("click", onAddExpenseButtonClick);
addCloseBtn.removeEventListener("click", onAddIncomeButtonClick);
window.removeEventListener("click", onCloseButtonClick);
}
}
// Function to open the modal and set the input values based on the clicked row
function openModalWithData(row, clickedCell) {
const name = row.cells[0].querySelector("input").value;
const income = row.cells[1].querySelector("input").value;
const account = row.cells[2].querySelector("input").value;
const source = row.cells[3].querySelector("input").value;
const date = row.cells[4].querySelector("input").value;
document.getElementById("nameInput").value = name;
document.getElementById("incomeInput").value = income;
document.getElementById("accountInput").value = account;
document.getElementById("sourceInput").value = source;
document.getElementById("dateInput").value = date;
removeEventListenersForButtons();
const incomeLabel = document.querySelector('label[for="incomeInput"]');
const sourceLabel = document.querySelector('label[for="sourceInput"]');
const addExpenseButton = document.getElementById("addExpenseButton");
const addIncomeButton = document.getElementById("addIncomeButton");
// Remove any previous event listeners before adding new ones
addExpenseButton.removeEventListener("click", onAddExpenseButtonClick);
addIncomeButton.removeEventListener("click", onAddIncomeButtonClick);
if (
row.parentElement === expenseTable.querySelector("tbody") &&
clickedCell.cellIndex === 3
) {
addExpenseButton.style.display = "block";
addIncomeButton.style.display = "none"; // Hide addIncomeButton
addExpenseButton.addEventListener("click", onAddExpenseButtonClick);
const saveButton = document.getElementById("save-btn");
saveButton.addEventListener("click", function () {
// Get the values from the input fields
console.log("Pressed this button")
const newSourceName = document.getElementById("newSourceInput").value;
const sourceDescription = document.getElementById("descriptionInput").value;
// Create a JSON object with the data to send to the server
const newIncomeSourceData = {
newSourceName: newSourceName,
description: sourceDescription,
};
// Send the data to the server using AJAX POST request
fetch("/add_expense_source", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newIncomeSourceData),
})
.then((response) => response.json())
.then((data) => {
console.log(data); // You can handle the server response here
addModal.style.display = "none"; // Close the modal
// Optionally, you can update the frontend to display the new income source in the list
// without having to refresh the page by adding the new data to the existing income sources list.
})
.catch((error) => {
console.error("Error:", error);
// Handle the error, display a message, etc.
});
});
} else if (
row.parentElement === table.querySelector("tbody") &&
clickedCell.cellIndex === 3
) {
addIncomeButton.style.display = "block";
addExpenseButton.style.display = "none"; // Hide addExpenseButton
const saveButton = document.getElementById("save-btn");
saveButton.addEventListener("click", function () {
// Get the values from the input fields
console.log("Pressed this button")
const newSourceName = document.getElementById("newSourceInput").value;
const sourceDescription = document.getElementById("descriptionInput").value;
// Create a JSON object with the data to send to the server
const newIncomeSourceData = {
newSourceName: newSourceName,
description: sourceDescription,
};
// Send the data to the server using AJAX POST request
fetch("/add_income_source", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newIncomeSourceData),
})
.then((response) => response.json())
.then((data) => {
console.log(data); // You can handle the server response here
addModal.style.display = "none"; // Close the modal
// Optionally, you can update the frontend to display the new income source in the list
// without having to refresh the page by adding the new data to the existing income sources list.
})
.catch((error) => {
console.error("Error:", error);
// Handle the error, display a message, etc.
});
});
addIncomeButton.addEventListener("click", onAddIncomeButtonClick);
} else {
addExpenseButton.style.display = "none";
addIncomeButton.style.display = "none";
}
// Check if the clicked row is part of the expense table
if (row.parentElement === expenseTable.querySelector("tbody")) {
incomeLabel.textContent = "Expense";
sourceLabel.textContent = "Expense Source";
} else {
// Set the label text back to "Income"
incomeLabel.textContent = "Income";
sourceLabel.textContent = "Income Source";
}
modal.style.display = "block";
currentRowIndex = row.rowIndex;
}
// Add a double-click event listener to the first table using event delegation
table.addEventListener("dblclick", function (event) {
const targetCell = event.target.closest("td");
if (targetCell) {
const row = targetCell.parentElement;
openModalWithData(row, targetCell);
}
});
// Add a double-click event listener to the second table using event delegation
expenseTable.addEventListener("dblclick", function (event) {
const targetCell = event.target.closest("td");
if (targetCell) {
const row = targetCell.parentElement;
openModalWithData(row, targetCell);
}
});
// Get the close button element and add a click event listener to close the modal
const closeBtn = document.getElementsByClassName("close")[0];
closeBtn.addEventListener("click", function () {
modal.style.display = "none";
addModal.style.display = "none";
});
// When the user clicks anywhere outside the modal, close it
window.addEventListener("click", onCloseButtonClick);
Editor is loading...