333 lines
8.3 KiB
Plaintext
333 lines
8.3 KiB
Plaintext
<% content_for :title, "Expense Report" %>
|
|
|
|
<style>
|
|
:root{
|
|
--card-bg: #ffffff;
|
|
--muted: #6b7280;
|
|
--accent: #f59e0b; /* Orange for expenses */
|
|
--radius: 10px;
|
|
--shadow: 0 6px 20px rgba(16,24,40,0.06);
|
|
--gap: 18px;
|
|
font-family: "Inter", "Poppins", system-ui;
|
|
}
|
|
|
|
.er-container {
|
|
max-width: 920px;
|
|
margin: 28px auto;
|
|
padding: 18px;
|
|
color: #111827;
|
|
}
|
|
|
|
.er-header {
|
|
display:flex;
|
|
align-items:center;
|
|
justify-content:space-between;
|
|
gap:12px;
|
|
margin-bottom: var(--gap);
|
|
}
|
|
|
|
.er-title {
|
|
color: #fff;
|
|
font-size:1.4rem;
|
|
font-weight:600;
|
|
margin:0;
|
|
}
|
|
|
|
.er-actions { display:flex; gap:10px; align-items:center; }
|
|
|
|
.btn-simple {
|
|
background: var(--accent);
|
|
color:#fff;
|
|
padding:8px 12px;
|
|
border-radius:8px;
|
|
text-decoration:none;
|
|
font-weight:600;
|
|
font-size:0.95rem;
|
|
box-shadow: 0 6px 16px rgba(249, 94, 11, 0.12);
|
|
transition: transform .12s ease, box-shadow .12s ease;
|
|
}
|
|
.btn-simple:hover { transform: translateY(-3px); box-shadow: 0 10px 26px rgba(249, 94, 11, 0.16); }
|
|
|
|
.summary-row {
|
|
display: flex;
|
|
gap: 16px;
|
|
margin-bottom: 22px;
|
|
}
|
|
|
|
.card {
|
|
flex: 1;
|
|
padding: 16px;
|
|
border-radius: var(--radius);
|
|
background: #f3f4f6;
|
|
border: 1px solid var(--border);
|
|
backdrop-filter: blur(12px);
|
|
box-shadow: var(--shadow);
|
|
transition: .25s;
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-6px) scale(1.02);
|
|
box-shadow: 0 12px 36px rgba(249, 94, 11, 0.75);
|
|
}
|
|
|
|
.card small {
|
|
color: var(--muted);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.card .value {
|
|
font-size: 1.4rem;
|
|
font-weight: 700;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
.chart-wrap {
|
|
background: var(--card-bg);
|
|
border-radius: var(--radius);
|
|
box-shadow: var(--shadow);
|
|
padding:12px;
|
|
margin-bottom: var(--gap);
|
|
border: 1px solid rgba(15,23,42,0.04);
|
|
}
|
|
|
|
.table {
|
|
width: 100%;
|
|
border-collapse: separate;
|
|
border-spacing: 0;
|
|
margin-bottom: 20px;
|
|
background: transparent;
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.table thead {
|
|
background: rgba(35, 39, 43, 0.98);
|
|
}
|
|
|
|
.table thead th {
|
|
text-align: left;
|
|
font-size: 0.9rem;
|
|
color: #562929;
|
|
padding: 12px 16px;
|
|
font-weight: 600;
|
|
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.table tbody tr {
|
|
background: rgba(35, 39, 43, 0.95);
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
.table tbody tr:hover {
|
|
background: rgba(45, 49, 53, 0.98);
|
|
}
|
|
|
|
.table td {
|
|
padding: 12px 16px;
|
|
font-size: 0.95rem;
|
|
color: #562929;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.table tbody tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.table tfoot {
|
|
background: rgba(35, 39, 43, 0.98);
|
|
}
|
|
|
|
.table tfoot th {
|
|
padding: 12px 16px;
|
|
text-align: left;
|
|
font-weight: 700;
|
|
color: #562929;
|
|
border-top: 2px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
/* Fix the "No expense" message color */
|
|
.table tbody tr td[colspan] {
|
|
color: #e0e0e0 !important;
|
|
text-align: center;
|
|
padding: 20px;
|
|
}
|
|
|
|
@media (max-width:720px){
|
|
.summary-row { flex-direction:column; }
|
|
.er-header { flex-direction:column; align-items:flex-start; gap:10px; }
|
|
}
|
|
</style>
|
|
|
|
<div class="er-container">
|
|
<div class="er-header">
|
|
<h1 class="er-title">EXPENSE REPORT</h1>
|
|
|
|
<div class="er-actions">
|
|
<%= link_to "New Expense", new_expense_path, class: "btn-simple" %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary -->
|
|
<div class="summary-row">
|
|
<div class="card">
|
|
<small>Today's Expense</small>
|
|
<div class="value"><%= number_to_currency(@daily_expense || 0, unit: "₹") %></div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<small>This Week</small>
|
|
<div class="value"><%= number_to_currency(@weekly_expense || 0, unit: "₹") %></div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<small>This Month</small>
|
|
<div class="value"><%= number_to_currency(@monthly_expense || 0, unit: "₹") %></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Chart -->
|
|
<div class="chart-wrap">
|
|
<canvas id="expenseChart" height="120"></canvas>
|
|
</div>
|
|
|
|
<!-- Today's table -->
|
|
<section>
|
|
<h3 style="margin:0 0 8px 0; font-size:1rem; color:#fff;">Today's Expenses</h3>
|
|
<table class="table">
|
|
<thead>
|
|
<tr><th>Title</th><th>Amount</th><th>Date</th><th>Description</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<% (@daily_expense_items || []).each do |expense| %>
|
|
<tr>
|
|
<td><%= expense.title %></td>
|
|
<td><%= number_to_currency(expense.amount, unit: "₹") %></td>
|
|
<td><%= expense.date.strftime("%d %b %Y") %></td>
|
|
<td><%= expense.description %></td>
|
|
</tr>
|
|
<% end %>
|
|
<% if (@daily_expense_items || []).empty? %>
|
|
<tr><td colspan="4" class="text-center">No expense for today.</td></tr>
|
|
<% end %>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<th>Total</th>
|
|
<th><%= number_to_currency(@daily_expense || 0, unit: "₹") %></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</section>
|
|
|
|
<!-- Week table -->
|
|
<section>
|
|
<h3 style="margin:0 0 8px 0; font-size:1rem; color:#fff;">This Week's Expenses</h3>
|
|
<table class="table">
|
|
<thead>
|
|
<tr><th>Title</th><th>Amount</th><th>Date</th><th>Description</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<% (@weekly_expense_items || []).each do |expense| %>
|
|
<tr>
|
|
<td><%= expense.title %></td>
|
|
<td><%= number_to_currency(expense.amount, unit: "₹") %></td>
|
|
<td><%= expense.date.strftime("%d %b %Y") %></td>
|
|
<td><%= expense.description %></td>
|
|
</tr>
|
|
<% end %>
|
|
<% if (@weekly_expense_items || []).empty? %>
|
|
<tr><td colspan="4" class="text-center">No expense for this week.</td></tr>
|
|
<% end %>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<th>Total</th>
|
|
<th><%= number_to_currency(@weekly_expense || 0, unit: "₹") %></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</section>
|
|
|
|
<!-- Month table -->
|
|
<section>
|
|
<h3 style="margin:0 0 8px 0; font-size:1rem; color:#fff;">This Month's Expenses</h3>
|
|
<table class="table">
|
|
<thead>
|
|
<tr><th>Title</th><th>Amount</th><th>Date</th><th>Description</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
<% (@monthly_expense_items || []).each do |expense| %>
|
|
<tr>
|
|
<td><%= expense.title %></td>
|
|
<td><%= number_to_currency(expense.amount, unit: "₹") %></td>
|
|
<td><%= expense.date.strftime("%d %b %Y") %></td>
|
|
<td><%= expense.description %></td>
|
|
</tr>
|
|
<% end %>
|
|
<% if (@monthly_expense_items || []).empty? %>
|
|
<tr><td colspan="4" class="text-center">No expense for this month.</td></tr>
|
|
<% end %>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<th>Total</th>
|
|
<th><%= number_to_currency(@monthly_expense || 0, unit: "₹") %></th>
|
|
<th></th>
|
|
<th></th>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</section>
|
|
</div>
|
|
|
|
<!-- Chart.js -->
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
(function(){
|
|
const labels = <%= raw((@chart_labels || []).to_json) %>;
|
|
const data = <%= raw((@chart_data || []).to_json) %>;
|
|
|
|
const ctx = document.getElementById('expenseChart').getContext('2d');
|
|
const gradient = ctx.createLinearGradient(0,0,0,120);
|
|
gradient.addColorStop(0, 'rgba(249,94,11,0.18)');
|
|
gradient.addColorStop(1, 'rgba(249,94,11,0)');
|
|
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: 'Expenses',
|
|
data: data,
|
|
fill: true,
|
|
backgroundColor: gradient,
|
|
borderColor: 'rgba(249,94,11,1)',
|
|
tension: 0.42,
|
|
borderWidth: 2,
|
|
pointRadius: 3,
|
|
pointBackgroundColor: 'rgba(249,94,11,1)'
|
|
}]
|
|
},
|
|
options: {
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
x: { ticks: { color: '#374151' } },
|
|
y: {
|
|
beginAtZero: true,
|
|
ticks: { callback: v => '₹' + v, color: '#374151' },
|
|
grid: { color: 'rgba(15,23,42,0.04)' }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: { callbacks: { label: ctx => '₹' + ctx.formattedValue } }
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
</script>
|