Resolve merge conflicts

This commit is contained in:
Utkarsh Khedkar
2026-02-17 14:44:47 +05:30
84 changed files with 16116 additions and 5486 deletions

View File

@@ -33,6 +33,401 @@
}
}
/* --------------------------------------------------
INVOICE PREVIEW RESPONSIVE FIXES
-------------------------------------------------- */
.invoice-preview-wrapper {
width: 100%;
overflow: auto;
max-width: 100%;
box-sizing: border-box;
}
.invoice-preview-wrapper * {
box-sizing: border-box;
}
/* Override any fixed width styles that might be in popup_invoice */
#invoicePreview,
.invoice-container,
.invoice-wrapper {
max-width: 100% !important;
width: 100% !important;
}
/* Responsive table fixes for invoice */
.invoice-preview-wrapper table {
width: 100% !important;
max-width: 100% !important;
table-layout: auto !important;
}
.invoice-preview-wrapper .table-responsive {
overflow-x: auto !important;
-webkit-overflow-scrolling: touch;
}
/* Ensure all elements scale properly */
.invoice-preview-wrapper .row,
.invoice-preview-wrapper .col,
.invoice-preview-wrapper [class*="col-"] {
flex: 1 1 auto !important;
max-width: 100% !important;
}
/* Force responsive behavior for print-style elements */
@media (max-width: 1200px) {
.invoice-preview-wrapper {
font-size: 95%;
}
}
@media (max-width: 992px) {
.invoice-preview-wrapper {
font-size: 90%;
}
}
@media (max-width: 768px) {
.invoice-preview-wrapper {
font-size: 85%;
}
.invoice-preview-wrapper table th,
.invoice-preview-wrapper table td {
padding: 0.5rem !important;
}
}
@media (max-width: 576px) {
.invoice-preview-wrapper {
font-size: 80%;
}
.invoice-preview-wrapper .d-flex {
flex-direction: column !important;
}
.invoice-preview-wrapper .text-end,
.invoice-preview-wrapper .text-start {
text-align: center !important;
}
}
/* Prevent any fixed pixel widths */
.invoice-preview-wrapper [style*="width:"]:not([style*="width:100%"]):not([style*="width:auto"]) {
width: auto !important;
max-width: 100% !important;
}
.invoice-preview-wrapper [style*="min-width"] {
min-width: 0 !important;
}
/* --------------------------------------------------
COMPACT CARD DESIGN
-------------------------------------------------- */
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(20px);
border-radius: var(--border-radius);
border: 1px solid var(--glass-border);
box-shadow: var(--shadow-strong);
position: relative;
overflow: hidden;
animation: fadeUp 0.6s ease;
margin-bottom: 1.5rem;
}
.glass-card::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(45deg,
rgba(102, 126, 234, 0.03),
rgba(118, 75, 162, 0.03) 50%,
rgba(16, 185, 129, 0.03));
pointer-events: none;
}
/* --------------------------------------------------
COMPACT CARD HEADER
-------------------------------------------------- */
.card-header-compact {
background: var(--primary-gradient);
color: #fff;
padding: 1rem 1.5rem;
border: none;
position: relative;
overflow: hidden;
}
.card-header-compact h4 {
margin: 0;
font-weight: 700;
font-size: 1.3rem;
display: flex;
align-items: center;
gap: 10px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
/* --------------------------------------------------
COMPACT CARD BODY
-------------------------------------------------- */
.card-body-compact {
padding: 1.5rem;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
position: relative;
z-index: 1;
}
/* --------------------------------------------------
COMPACT FORM ELEMENTS
-------------------------------------------------- */
.form-grid-compact {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.form-group-compact {
position: relative;
}
.form-label-compact {
font-weight: 600;
color: #374151;
margin-bottom: 8px;
font-size: 0.9rem;
display: flex;
align-items: center;
gap: 8px;
}
.form-control-compact, .form-select-compact {
border: 2px solid #e2e8f0;
border-radius: 8px;
padding: 10px 12px;
font-size: 0.9rem;
transition: all 0.3s ease;
background: white;
width: 100%;
}
.form-control-compact:focus, .form-select-compact:focus {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
outline: none;
}
/* --------------------------------------------------
COMPACT BUTTONS
-------------------------------------------------- */
.btn-compact {
padding: 10px 20px;
border-radius: 8px;
font-weight: 600;
font-size: 0.9rem;
transition: all 0.3s ease;
border: none;
display: inline-flex;
align-items: center;
gap: 6px;
text-decoration: none;
}
.btn-success-compact {
background: var(--success-gradient);
color: white;
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}
.btn-success-compact:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(16, 185, 129, 0.4);
color: white;
}
.btn-primary-compact {
background: var(--primary-gradient);
color: white;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn-primary-compact:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
color: white;
}
.btn-danger-compact {
background: var(--danger-gradient);
color: white;
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
}
.btn-danger-compact:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(239, 68, 68, 0.4);
color: white;
}
.btn-info-compact {
background: linear-gradient(135deg, #06b6d4 0%, #0ea5e9 100%);
color: white;
box-shadow: 0 4px 12px rgba(6, 182, 212, 0.3);
}
.btn-info-compact:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(6, 182, 212, 0.4);
color: white;
}
.btn-warning-compact {
background: var(--warning-gradient);
color: white;
box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
}
.btn-warning-compact:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(245, 158, 11, 0.4);
color: white;
}
/* --------------------------------------------------
COMPACT SUMMARY CARDS
-------------------------------------------------- */
.summary-grid-compact {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.summary-card-compact {
background: white;
padding: 1rem;
border-radius: 8px;
box-shadow: var(--shadow-soft);
border-left: 4px solid;
text-align: center;
}
.summary-card-compact.total { border-left-color: #10b981; }
.summary-card-compact.paid { border-left-color: #3b82f6; }
.summary-card-compact.remaining { border-left-color: #f59e0b; }
.summary-value-compact {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.25rem;
}
.summary-label-compact {
font-size: 0.8rem;
color: #64748b;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* --------------------------------------------------
COMPACT AMOUNT BREAKDOWN
-------------------------------------------------- */
.amount-breakdown-compact {
background: white;
padding: 1.5rem;
border-radius: 8px;
box-shadow: var(--shadow-soft);
margin-bottom: 1.5rem;
}
.breakdown-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 0;
border-bottom: 1px solid #f1f5f9;
}
.breakdown-row:last-child {
border-bottom: none;
}
.breakdown-label {
font-weight: 600;
color: #374151;
font-size: 0.9rem;
}
.breakdown-value {
font-weight: 600;
font-size: 0.9rem;
}
/* --------------------------------------------------
COMPACT TABLE
-------------------------------------------------- */
.table-compact {
width: 100%;
border-collapse: collapse;
margin-bottom: 0;
font-size: 0.85rem;
}
.table-compact thead th {
background: var(--primary-gradient);
color: white;
padding: 0.75rem 1rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
font-size: 0.8rem;
border: none;
}
.table-compact tbody tr {
background: white;
transition: all 0.2s ease;
}
.table-compact tbody tr:hover {
background: #f8fafc;
}
.table-compact tbody td {
padding: 0.75rem 1rem;
border-bottom: 1px solid #e2e8f0;
vertical-align: middle;
}
/* --------------------------------------------------
BADGE STYLES
-------------------------------------------------- */
.badge-compact {
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
}
/* --------------------------------------------------
HEADER ACTION BUTTONS
-------------------------------------------------- */
.header-actions {
display: flex;
gap: 0.75rem;
align-items: center;
}
/* --------------------------------------------------
RESPONSIVE DESIGN
-------------------------------------------------- */
@media (max-width: 768px) {
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(20px);
@@ -309,16 +704,59 @@
font-size: 0.8rem;
}
}
.header-actions {
flex-direction: column;
width: 100%;
gap: 0.5rem;
margin-top: 0.5rem;
}
}
@media print {
.invoice-preview-wrapper {
max-width: 100% !important;
width: 100% !important;
overflow: visible !important;
}
.invoice-preview-wrapper * {
visibility: visible !important;
}
.glass-card {
box-shadow: none !important;
border: 1px solid #000 !important;
}
.card-header-compact {
background: #000 !important;
color: #fff !important;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
</style>
<div class="container-fluid py-3">
{{-- Invoice Preview / Overview --}}
<div class="glass-card">
<div class="card-header-compact">
<div class="card-header-compact d-flex justify-content-between align-items-center">
<h4>
<i class="fas fa-file-invoice me-2"></i>
Invoice Overview
</h4>
<div class="header-actions">
<!-- Share Invoice -->
<button class="btn-info-compact btn-compact" id="shareInvoiceBtn">
<i class="fas fa-share-alt me-2"></i>Share Invoice
</button>
<!-- Download Invoice -->
<a href="{{ route('admin.invoices.download', $invoice->id) }}"
class="btn-warning-compact btn-compact" target="_blank">
<i class="fas fa-download me-2"></i>Download Invoice
</a>
</div>
</div>
<div class="card-body-compact">
{{-- इथे popup_invoice मधूनच items table (editable) येईल --}}
@@ -459,6 +897,7 @@
</div>
</div>
<<<<<<< HEAD
@php
$totalPaid = $invoice->installments()->sum('amount');
$remaining = $invoice->final_amount_with_gst - $totalPaid;
@@ -551,6 +990,9 @@
</div>
{{-- Installment Management --}}
=======
<!-- Installment Management -->
>>>>>>> 8b6d3d5fadadda310ef45ec03c879b900bff4cb025f45d1bb5d188761d53e043
<div class="glass-card">
<div class="card-header-compact d-flex justify-content-between align-items-center">
<h4 class="mb-0">
@@ -643,12 +1085,7 @@
<h6 class="fw-bold mb-2 text-dark">
<i class="fas fa-history me-2"></i>Installment History
</h6>
<div id="noInstallmentsMsg"
class="{{ $invoice->installments->count() ? 'd-none' : '' }} text-center text-muted fw-bold py-4">
No installments found. Click Add Installment to create one.
</div>
@if($invoice->installments->count() > 0)
<div class="table-responsive">
<table class="table-compact">
<thead>
@@ -691,6 +1128,11 @@
</tbody>
</table>
</div>
@else
<div id="noInstallmentsMsg" class="text-center text-muted fw-bold py-4">
No installments found. Click "Add Installment" to create one.
</div>
@endif
</div>
</div>
</div>
@@ -717,6 +1159,7 @@ document.addEventListener("DOMContentLoaded", function () {
});
};
<<<<<<< HEAD
if (submitForm && submitBtn) {
submitForm.addEventListener("submit", function (e) {
e.preventDefault();
@@ -825,12 +1268,131 @@ document.addEventListener("DOMContentLoaded", function () {
const id = row.getAttribute("data-id");
fetch("{{ url('admin/installment') }}/" + id, {
=======
if (submitForm) {
submitForm.addEventListener("submit", function (e) {
e.preventDefault();
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Processing...';
submitBtn.disabled = true;
fetch("{{ route('admin.invoice.installment.store', $invoice->id) }}", {
method: "POST",
headers: {
"X-CSRF-TOKEN": submitForm.querySelector("input[name=_token]").value,
"Accept": "application/json"
},
body: new FormData(submitForm)
})
.then(res => res.json())
.then(data => {
submitBtn.innerHTML = '<i class="fas fa-paper-plane me-2"></i>Submit Installment';
submitBtn.disabled = false;
if (data.status === "error") {
alert(data.message);
return;
}
const table = document.querySelector("#installmentTable");
const noInstallmentsMsg = document.getElementById("noInstallmentsMsg");
if (noInstallmentsMsg) {
noInstallmentsMsg.classList.add("d-none");
}
if (!table) {
// Create table if it doesn't exist
const tableHTML = `
<div class="table-responsive">
<table class="table-compact">
<thead>
<tr>
<th>#</th>
<th>Date</th>
<th>Payment Method</th>
<th>Reference No</th>
<th>Amount</th>
<th>Action</th>
</tr>
</thead>
<tbody id="installmentTable">
</tbody>
</table>
</div>
`;
const parent = submitForm.closest('.card-body-compact');
parent.insertAdjacentHTML('beforeend', tableHTML);
}
const newTable = document.querySelector("#installmentTable");
const index = newTable.rows.length + 1;
newTable.insertAdjacentHTML("beforeend", `
<tr data-id="${data.installment.id}">
<td class="fw-bold text-muted">${index}</td>
<td>${data.installment.installment_date}</td>
<td>
<span class="badge-compact bg-primary bg-opacity-10 text-primary">
${data.installment.payment_method.toUpperCase()}
</span>
</td>
<td>${data.installment.reference_no || '-'}</td>
<td class="fw-bold text-success">${formatINR(data.installment.amount)}</td>
<td>
<button class="btn-danger-compact btn-compact btn-sm deleteInstallment">
<i class="fas fa-trash me-1"></i>Delete
</button>
</td>
</tr>
`);
// Update all displayed values
if (document.getElementById("paidAmount")) document.getElementById("paidAmount").textContent = formatINR(data.totalPaid);
if (document.getElementById("remainingAmount")) document.getElementById("remainingAmount").textContent = formatINR(data.remaining);
// Update summary cards
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
if (paidCard) paidCard.textContent = formatINR(data.totalPaid);
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
if (remainingCard) remainingCard.textContent = formatINR(data.remaining);
submitForm.reset();
// If fully paid, disable/add display logic
if (data.isCompleted) {
toggleBtn?.remove();
formBox.classList.add("d-none");
}
alert(data.message);
})
.catch(() => {
submitBtn.innerHTML = '<i class="fas fa-paper-plane me-2"></i>Submit Installment';
submitBtn.disabled = false;
alert("Something went wrong. Please try again.");
});
});
}
// Delete Installment
document.addEventListener("click", function (e) {
if (!e.target.classList.contains("deleteInstallment")) return;
if (!confirm("Are you sure you want to delete this installment?")) return;
const row = e.target.closest("tr");
const id = row.getAttribute("data-id");
fetch("{{ url('/admin/installment') }}/" + id, {
>>>>>>> 8b6d3d5fadadda310ef45ec03c879b900bff4cb025f45d1bb5d188761d53e043
method: "DELETE",
headers: {
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').getAttribute("content"),
"Accept": "application/json",
},
})
<<<<<<< HEAD
.then(res => res.json())
.then(data => {
if (data.status === "success") {
@@ -858,6 +1420,49 @@ document.addEventListener("DOMContentLoaded", function () {
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
if (remainingCard) remainingCard.textContent = "" + formatINR(data.remaining);
=======
.then(res => res.json())
.then(data => {
if (data.status === "success") {
row.style.opacity = "0";
setTimeout(() => {
row.remove();
// Update row numbers
const rows = document.querySelectorAll("#installmentTable tr");
rows.forEach((row, index) => {
row.querySelector("td:first-child").textContent = index + 1;
});
// Show no installments message if empty
if (rows.length === 0) {
const noInstallmentsMsg = document.getElementById("noInstallmentsMsg");
if (noInstallmentsMsg) {
noInstallmentsMsg.classList.remove("d-none");
}
}
}, 300);
// Update all displayed values
if (document.getElementById("paidAmount")) document.getElementById("paidAmount").textContent = formatINR(data.totalPaid);
if (document.getElementById("remainingAmount")) document.getElementById("remainingAmount").textContent = formatINR(data.remaining);
// Update summary cards
const paidCard = document.querySelector(".summary-card-compact.paid .summary-value-compact");
if (paidCard) paidCard.textContent = formatINR(data.totalPaid);
const remainingCard = document.querySelector(".summary-card-compact.remaining .summary-value-compact");
if (remainingCard) remainingCard.textContent = formatINR(data.remaining);
// Show add installment button if there's remaining amount
if (data.remaining > 0 && !document.getElementById("toggleInstallmentForm")) {
const header = document.querySelector(".glass-card .card-header-compact");
header.innerHTML += `
<button id="toggleInstallmentForm" class="btn-primary-compact btn-compact">
<i class="fas fa-plus-circle me-2"></i>Add Installment
</button>
`;
}
>>>>>>> 8b6d3d5fadadda310ef45ec03c879b900bff4cb025f45d1bb5d188761d53e043
if (data.isZero) {
document.getElementById("noInstallmentsMsg")?.classList.remove("d-none");
@@ -874,4 +1479,8 @@ document.addEventListener("DOMContentLoaded", function () {
});
});
</script>
<<<<<<< HEAD
@endsection
=======
@endsection
>>>>>>> 8b6d3d5fadadda310ef45ec03c879b900bff4cb025f45d1bb5d188761d53e043