Add Container field
This commit is contained in:
@@ -1,12 +1,94 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('page-title', 'Dashboard')
|
||||
@section('page-title', 'Chat Support')
|
||||
|
||||
@section('content')
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h4>Welcome to the Admin chat</h4>
|
||||
<p>Here you can manage all system modules.</p>
|
||||
</div>
|
||||
|
||||
<div class="container py-4">
|
||||
|
||||
<h2 class="mb-4 fw-bold">Customer Support Chat</h2>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-0">
|
||||
|
||||
@if($tickets->count() === 0)
|
||||
<div class="p-4 text-center text-muted">
|
||||
<h5>No customer chats yet.</h5>
|
||||
</div>
|
||||
@else
|
||||
<ul class="list-group list-group-flush">
|
||||
|
||||
@foreach($tickets as $ticket)
|
||||
@php
|
||||
// Get last message
|
||||
$lastMsg = $ticket->messages()->latest()->first();
|
||||
@endphp
|
||||
|
||||
<li class="list-group-item py-3">
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
|
||||
<!-- Left side: User info + last message -->
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
|
||||
<!-- Profile Circle -->
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center"
|
||||
style="width: 45px; height: 45px; font-size: 18px;">
|
||||
{{ strtoupper(substr($ticket->user->customer_name ?? $ticket->user->name, 0, 1)) }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- Customer Name -->
|
||||
<h6 class="mb-1 fw-semibold">
|
||||
{{ $ticket->user->customer_name ?? $ticket->user->name }}
|
||||
</h6>
|
||||
|
||||
<!-- Last message preview -->
|
||||
<small class="text-muted">
|
||||
@if($lastMsg)
|
||||
@if($lastMsg->message)
|
||||
{{ Str::limit($lastMsg->message, 35) }}
|
||||
@elseif($lastMsg->file_type === 'image')
|
||||
📷 Image
|
||||
@elseif($lastMsg->file_type === 'video')
|
||||
🎥 Video
|
||||
@else
|
||||
📎 Attachment
|
||||
@endif
|
||||
@else
|
||||
<i>No messages yet</i>
|
||||
@endif
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right Side: Status + Button -->
|
||||
<div class="text-end">
|
||||
|
||||
<!-- Ticket Status -->
|
||||
<span class="badge
|
||||
{{ $ticket->status === 'open' ? 'bg-success' : 'bg-danger' }}">
|
||||
{{ ucfirst($ticket->status) }}
|
||||
</span>
|
||||
|
||||
<!-- Open Chat Button -->
|
||||
<a href="{{ route('admin.chat.open', $ticket->id) }}"
|
||||
class="btn btn-sm btn-primary ms-2">
|
||||
Open Chat →
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
201
resources/views/admin/chat_window.blade.php
Normal file
201
resources/views/admin/chat_window.blade.php
Normal file
@@ -0,0 +1,201 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('page-title', 'Chat With ' . ($ticket->user->customer_name ?? $ticket->user->name))
|
||||
|
||||
@section('content')
|
||||
|
||||
<style>
|
||||
.chat-box {
|
||||
height: 70vh;
|
||||
overflow-y: auto;
|
||||
background: #f5f6fa;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
}
|
||||
.message {
|
||||
max-width: 65%;
|
||||
padding: 10px 14px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.message.admin {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
margin-left: auto;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.message.user {
|
||||
background: #ffffff;
|
||||
border: 1px solid #ddd;
|
||||
margin-right: auto;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.chat-input {
|
||||
position: fixed;
|
||||
bottom: 15px;
|
||||
left: 250px;
|
||||
right: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container py-4">
|
||||
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<h4 class="fw-bold mb-0">
|
||||
Chat With: {{ $ticket->user->customer_name ?? $ticket->user->name }}
|
||||
</h4>
|
||||
<span class="badge ms-3 {{ $ticket->status === 'open' ? 'bg-success' : 'bg-danger' }}">
|
||||
{{ ucfirst($ticket->status) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="chatBox" class="chat-box border shadow-sm">
|
||||
|
||||
@foreach($messages as $msg)
|
||||
<div class="message {{ $msg->sender_type === 'App\\Models\\Admin' ? 'admin' : 'user' }}">
|
||||
|
||||
{{-- TEXT --}}
|
||||
@if($msg->message)
|
||||
<div>{{ $msg->message }}</div>
|
||||
@endif
|
||||
|
||||
{{-- FILE --}}
|
||||
@if($msg->file_path)
|
||||
<div class="mt-2">
|
||||
@php $isImage = Str::startsWith($msg->file_type, 'image'); @endphp
|
||||
|
||||
@if($isImage)
|
||||
<img src="{{ asset('storage/'.$msg->file_path) }}" style="max-width:150px;" class="rounded">
|
||||
@else
|
||||
<a href="{{ asset('storage/'.$msg->file_path) }}" target="_blank">📎 View Attachment</a>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<small class="text-muted d-block mt-1">
|
||||
{{ $msg->created_at->format('d M h:i A') }}
|
||||
</small>
|
||||
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
<div class="chat-input">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body d-flex align-items-center gap-2">
|
||||
<input type="text" id="messageInput" class="form-control" placeholder="Type your message...">
|
||||
<input type="file" id="fileInput" class="form-control" style="max-width:200px;">
|
||||
<button class="btn btn-primary" id="sendBtn">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
console.log("CHAT WINDOW: script loaded");
|
||||
|
||||
// -------------------------------
|
||||
// WAIT FOR ECHO READY
|
||||
// -------------------------------
|
||||
function waitForEcho(callback, retries = 40) {
|
||||
if (window.Echo) {
|
||||
console.log("%c[ECHO] Ready!", "color: green; font-weight: bold;", window.Echo);
|
||||
return callback();
|
||||
}
|
||||
|
||||
console.warn("[ECHO] Not ready. Retrying...");
|
||||
if (retries <= 0) {
|
||||
console.error("[ECHO] FAILED to initialize after retry limit");
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => waitForEcho(callback, retries - 1), 200);
|
||||
}
|
||||
|
||||
// Scroll chat down
|
||||
function scrollToBottom() {
|
||||
const el = document.getElementById("chatBox");
|
||||
if (el) el.scrollTop = el.scrollHeight;
|
||||
}
|
||||
scrollToBottom();
|
||||
|
||||
// -------------------------------
|
||||
// SEND MESSAGE (WORKING PART FROM SCRIPT #1)
|
||||
// -------------------------------
|
||||
document.getElementById("sendBtn").addEventListener("click", function () {
|
||||
console.log("[SEND] Attempting to send message...");
|
||||
|
||||
let msg = document.getElementById("messageInput").value;
|
||||
let file = document.getElementById("fileInput").files[0];
|
||||
|
||||
if (!msg.trim() && !file) {
|
||||
alert("Please type something or upload a file.");
|
||||
return;
|
||||
}
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append("message", msg);
|
||||
if (file) formData.append("file", file);
|
||||
|
||||
fetch("{{ route('admin.chat.send', $ticket->id) }}", {
|
||||
method: "POST",
|
||||
headers: { "X-CSRF-TOKEN": "{{ csrf_token() }}" },
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then((response) => {
|
||||
console.log("[SEND] Message sent:", response);
|
||||
document.getElementById("messageInput").value = "";
|
||||
document.getElementById("fileInput").value = "";
|
||||
})
|
||||
.catch(err => console.error("[SEND] Error:", err));
|
||||
});
|
||||
|
||||
// -------------------------------
|
||||
// LISTEN FOR REALTIME MESSAGE (WORKING PART FROM SCRIPT #2)
|
||||
// -------------------------------
|
||||
waitForEcho(() => {
|
||||
const ticketId = "{{ $ticket->id }}";
|
||||
|
||||
console.log("[ECHO] Subscribing to channel:", `ticket.${ticketId}`);
|
||||
|
||||
window.Echo.private(`ticket.${ticketId}`)
|
||||
.listen("NewChatMessage", (event) => {
|
||||
|
||||
console.log("%c[REALTIME RECEIVED]", "color: blue; font-weight: bold;", event);
|
||||
|
||||
const msg = event.message;
|
||||
|
||||
let html = `
|
||||
<div class="message ${msg.sender_type === 'App\\Models\\Admin' ? 'admin' : 'user'}">
|
||||
${msg.message ?? ''}
|
||||
`;
|
||||
|
||||
if (msg.file_url) {
|
||||
if (msg.file_type.startsWith("image")) {
|
||||
html += `<img src="${msg.file_url}" class="rounded mt-2" style="max-width:150px;">`;
|
||||
} else {
|
||||
html += `<a href="${msg.file_url}" target="_blank" class="mt-2 d-block">📎 View File</a>`;
|
||||
}
|
||||
}
|
||||
|
||||
html += `
|
||||
<small class="text-muted d-block mt-1">Just now</small>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById("chatBox").innerHTML += html;
|
||||
scrollToBottom();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
710
resources/views/admin/container.blade.php
Normal file
710
resources/views/admin/container.blade.php
Normal file
@@ -0,0 +1,710 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('page-title', 'Containers')
|
||||
|
||||
@section('content')
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #4c6fff;
|
||||
--primary-gradient: linear-gradient(135deg, #4c6fff, #8e54e9);
|
||||
--success-color: #10b981;
|
||||
--warning-color: #f59e0b;
|
||||
--danger-color: #ef4444;
|
||||
--info-color: #3b82f6;
|
||||
--light-bg: #f8fafc;
|
||||
--dark-text: #1e293b;
|
||||
--gray-text: #64748b;
|
||||
--border-color: #e2e8f0;
|
||||
--shadow-sm: 0 1px 3px rgba(0,0,0,0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1);
|
||||
--shadow-lg: 0 10px 25px -5px rgba(0,0,0,0.1);
|
||||
--radius-lg: 16px;
|
||||
--radius-md: 12px;
|
||||
--radius-sm: 8px;
|
||||
}
|
||||
|
||||
.containers-wrapper {
|
||||
min-height: calc(100vh - 180px);
|
||||
padding: 20px 15px;
|
||||
background: linear-gradient(135deg, #f6f9ff 0%, #f0f4ff 100%);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
background: var(--primary-gradient);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.header-subtitle {
|
||||
color: var(--gray-text);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.add-container-btn {
|
||||
background: var(--primary-gradient);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 28px;
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
box-shadow: 0 4px 12px rgba(76, 111, 255, 0.3);
|
||||
}
|
||||
|
||||
.add-container-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(76, 111, 255, 0.4);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.add-container-btn i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.filter-card {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
margin-bottom: 30px;
|
||||
box-shadow: var(--shadow-lg);
|
||||
border: 1px solid rgba(255,255,255,0.9);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.filter-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--dark-text);
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.filter-title i {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.filter-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filter-group label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--gray-text);
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.filter-input, .filter-select, .filter-date {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 14px;
|
||||
color: var(--dark-text);
|
||||
background: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.filter-input:focus, .filter-select:focus, .filter-date:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(76, 111, 255, 0.1);
|
||||
}
|
||||
|
||||
.filter-input::placeholder {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.filter-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.apply-btn {
|
||||
background: var(--primary-gradient);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 46px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.apply-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 20px rgba(76, 111, 255, 0.3);
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: white;
|
||||
color: var(--gray-text);
|
||||
border: 2px solid var(--border-color);
|
||||
padding: 12px 24px;
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
min-height: 46px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.reset-btn:hover {
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.main-card {
|
||||
background: white;
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-lg);
|
||||
margin-bottom: 30px;
|
||||
border: 1px solid rgba(255,255,255,0.9);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 24px;
|
||||
background: linear-gradient(135deg, #4c6fff, #8e54e9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.card-header h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.card-header h2 i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.stats-badge {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
margin-left: 10px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.container-item {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
transition: all 0.3s ease;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.container-item:hover {
|
||||
background: #f8fafc;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.container-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.container-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.container-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.container-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary-gradient);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 12px rgba(76, 111, 255, 0.3);
|
||||
}
|
||||
|
||||
.container-details h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--dark-text);
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.container-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-size: 12px;
|
||||
color: var(--gray-text);
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.meta-item i {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 6px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.3px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.status-badge i {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.status-in-progress {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.view-btn {
|
||||
background: #e0f2fe;
|
||||
color: #0369a1;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.view-btn:hover {
|
||||
background: #0ea5e9;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
border: 1px solid #fecaca;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background: #dc2626;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.update-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.status-select {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 13px;
|
||||
color: var(--dark-text);
|
||||
background: white;
|
||||
min-width: 140px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.update-btn {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.update-btn:hover {
|
||||
background: #3b5de6;
|
||||
}
|
||||
|
||||
.no-results {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
.no-results-icon {
|
||||
font-size: 64px;
|
||||
color: var(--border-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.no-results h4 {
|
||||
font-size: 18px;
|
||||
color: var(--gray-text);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.no-results p {
|
||||
color: #94a3b8;
|
||||
font-size: 14px;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
padding: 16px 24px;
|
||||
border-radius: var(--radius-md);
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
box-shadow: var(--shadow-md);
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.success-message i {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from { opacity: 0; transform: translateY(-10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* 🔥 Totals section */
|
||||
.totals-section {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
||||
border-radius: var(--radius-md);
|
||||
border-left: 4px solid var(--primary-color);
|
||||
}
|
||||
|
||||
.total-card {
|
||||
text-align: center;
|
||||
padding: 12px;
|
||||
background: white;
|
||||
border-radius: var(--radius-sm);
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.total-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.total-value {
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.total-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--gray-text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
.add-container-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
.filter-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.container-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
.action-buttons {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.update-form {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
.status-select, .update-btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="containers-wrapper">
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Container Management</h1>
|
||||
<div class="header-subtitle">
|
||||
Manage all containers, track status, and view entries in real-time
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{ route('containers.create') }}" class="add-container-btn">
|
||||
<i class="fas fa-plus-circle"></i>
|
||||
Add New Container
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="success-message">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>{{ session('success') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="filter-card">
|
||||
<div class="filter-title">
|
||||
<i class="fas fa-filter"></i>
|
||||
Filter Containers
|
||||
</div>
|
||||
<form method="GET" class="filter-grid">
|
||||
<div class="filter-group">
|
||||
<label><i class="fas fa-search"></i> Search</label>
|
||||
<input type="text" name="search" class="filter-input"
|
||||
placeholder="Search by container name or number..."
|
||||
value="{{ request('search') }}">
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label><i class="fas fa-tag"></i> Status</label>
|
||||
<select name="status" class="filter-select">
|
||||
<option value="">All Status</option>
|
||||
<option value="pending" {{ request('status') == 'pending' ? 'selected' : '' }}>Pending</option>
|
||||
<option value="in-progress" {{ request('status') == 'in-progress' ? 'selected' : '' }}>In Progress</option>
|
||||
<option value="completed" {{ request('status') == 'completed' ? 'selected' : '' }}>Completed</option>
|
||||
<option value="cancelled" {{ request('status') == 'cancelled' ? 'selected' : '' }}>Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label><i class="fas fa-calendar"></i> Date</label>
|
||||
<input type="date" name="date" class="filter-date" value="{{ request('date') }}">
|
||||
</div>
|
||||
|
||||
<div class="filter-actions">
|
||||
<button type="submit" class="apply-btn">
|
||||
<i class="fas fa-search"></i> Apply Filters
|
||||
</button>
|
||||
<a href="{{ route('containers.index') }}" class="reset-btn">
|
||||
<i class="fas fa-redo"></i> Reset
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="main-card">
|
||||
<div class="card-header">
|
||||
<h2>
|
||||
<i class="fas fa-boxes"></i>
|
||||
Containers List
|
||||
<span class="stats-badge">{{ $containers->count() }} containers</span>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@if($containers->isEmpty())
|
||||
<div class="no-results">
|
||||
<div class="no-results-icon">
|
||||
<i class="fas fa-box-open"></i>
|
||||
</div>
|
||||
<h4>No containers found</h4>
|
||||
<p>Get started by creating your first container</p>
|
||||
</div>
|
||||
@else
|
||||
@foreach($containers as $container)
|
||||
@php
|
||||
$status = $container->status;
|
||||
$statusClass = match ($status) {
|
||||
'completed' => 'status-completed',
|
||||
'in-progress' => 'status-in-progress',
|
||||
'cancelled' => 'status-cancelled',
|
||||
default => 'status-pending',
|
||||
};
|
||||
@endphp
|
||||
|
||||
<div class="container-item">
|
||||
<div class="container-header">
|
||||
<div class="container-info">
|
||||
<div class="container-avatar">
|
||||
{{ substr($container->container_name, 0, 2) }}
|
||||
</div>
|
||||
<div class="container-details">
|
||||
<h3>{{ $container->container_name }}</h3>
|
||||
<div class="container-meta">
|
||||
<div class="meta-item">
|
||||
<i class="fas fa-hashtag"></i>
|
||||
<span>{{ $container->container_number }}</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<i class="fas fa-calendar"></i>
|
||||
<span>{{ $container->container_date?->format('M d, Y') ?: 'No date' }}</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<i class="fas fa-list"></i>
|
||||
<span>{{ $container->rows->count() }} entries</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<span class="status-badge {{ $statusClass }}">
|
||||
<i class="fas fa-circle"></i>
|
||||
{{ ucfirst(str_replace('-', ' ', $status)) }}
|
||||
</span>
|
||||
|
||||
<a href="{{ route('containers.show', $container->id) }}" class="action-btn view-btn">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</a>
|
||||
|
||||
<form action="{{ route('containers.update-status', $container->id) }}"
|
||||
method="POST" class="update-form">
|
||||
@csrf
|
||||
<select name="status" class="status-select">
|
||||
<option value="pending" {{ $status === 'pending' ? 'selected' : '' }}>Pending</option>
|
||||
<option value="in-progress" {{ $status === 'in-progress' ? 'selected' : '' }}>In Progress</option>
|
||||
<option value="completed" {{ $status === 'completed' ? 'selected' : '' }}>Completed</option>
|
||||
<option value="cancelled" {{ $status === 'cancelled' ? 'selected' : '' }}>Cancelled</option>
|
||||
</select>
|
||||
<button type="submit" class="update-btn">
|
||||
<i class="fas fa-sync-alt"></i> Update
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<form action="{{ route('containers.destroy', $container->id) }}" method="POST"
|
||||
onsubmit="return confirm('Are you sure you want to delete this container and all its entries?');">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="action-btn delete-btn">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 🔥 Totals instead of first row preview -->
|
||||
<div class="totals-section">
|
||||
<div class="total-card">
|
||||
<div class="total-value">{{ number_format($container->summary['total_ctn'], 1) }}</div>
|
||||
<div class="total-label">Total CTN</div>
|
||||
</div>
|
||||
<div class="total-card">
|
||||
<div class="total-value">{{ number_format($container->summary['total_qty'], 0) }}</div>
|
||||
<div class="total-label">Total QTY</div>
|
||||
</div>
|
||||
<div class="total-card">
|
||||
<div class="total-value">{{ number_format($container->summary['total_cbm'], 3) }}</div>
|
||||
<div class="total-label">Total CBM</div>
|
||||
</div>
|
||||
<div class="total-card">
|
||||
<div class="total-value">{{ number_format($container->summary['total_kg'], 1) }}</div>
|
||||
<div class="total-label">Total KG</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
|
||||
@endsection
|
||||
251
resources/views/admin/container_create.blade.php
Normal file
251
resources/views/admin/container_create.blade.php
Normal file
@@ -0,0 +1,251 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('page-title', 'Add Container')
|
||||
|
||||
@section('content')
|
||||
<style>
|
||||
.cm-add-wrapper {
|
||||
padding: 10px 0 20px 0;
|
||||
}
|
||||
|
||||
.cm-add-header-card {
|
||||
border-radius: 14px;
|
||||
border: none;
|
||||
margin-bottom: 18px;
|
||||
background: linear-gradient(90deg,#4c6fff,#8e54e9);
|
||||
box-shadow: 0 6px 18px rgba(15,35,52,0.18);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cm-add-header-card .card-body {
|
||||
padding: 14px 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.cm-add-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cm-add-sub {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.cm-add-main-card {
|
||||
border-radius: 14px;
|
||||
border: none;
|
||||
box-shadow: 0 6px 18px rgba(15,35,52,0.12);
|
||||
}
|
||||
|
||||
.cm-add-main-card .card-header {
|
||||
background:#ffffff;
|
||||
border-bottom: 1px solid #edf0f5;
|
||||
padding: 10px 18px;
|
||||
}
|
||||
|
||||
.cm-add-main-card .card-header h5 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cm-form-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color:#495057;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.cm-form-control {
|
||||
font-size: 13px;
|
||||
border-radius: 10px;
|
||||
border:1px solid #d0d7e2;
|
||||
padding: 8px 11px;
|
||||
}
|
||||
|
||||
.cm-form-control:focus {
|
||||
border-color:#4c6fff;
|
||||
box-shadow:0 0 0 0.15rem rgba(76,111,255,.25);
|
||||
}
|
||||
|
||||
.cm-help-text {
|
||||
font-size: 11px;
|
||||
color:#868e96;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.cm-btn-primary {
|
||||
border-radius: 20px;
|
||||
padding: 6px 22px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.cm-btn-secondary {
|
||||
border-radius: 20px;
|
||||
padding: 6px 18px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.cm-error-list {
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid cm-add-wrapper">
|
||||
|
||||
{{-- TOP GRADIENT HEADER --}}
|
||||
<div class="card cm-add-header-card">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<h4 class="cm-add-title">Create New Container</h4>
|
||||
<div class="cm-add-sub">
|
||||
Add container details and upload Kent loading list Excel file.
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{ route('containers.index') }}" class="btn btn-light btn-sm">
|
||||
Back to Containers
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- MAIN CARD --}}
|
||||
<div class="card cm-add-main-card">
|
||||
<div class="card-header">
|
||||
<h5>Add Container</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
{{-- SUCCESS MESSAGE --}}
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- VALIDATION ERRORS --}}
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<ul class="mb-0 cm-error-list">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- UNMATCHED ROWS TABLE --}}
|
||||
@if (session('unmatched_rows'))
|
||||
<div class="alert alert-warning mt-3">
|
||||
<strong>Mark number not matched:</strong>
|
||||
|
||||
|
||||
@php
|
||||
$unmatchedRows = session('unmatched_rows');
|
||||
$headings = [];
|
||||
if (!empty($unmatchedRows)) {
|
||||
$headings = array_keys($unmatchedRows[0]['data'] ?? []);
|
||||
// इथे Excel मधला 'MARK' कॉलम hide करतो, कारण आधीच Mark No वेगळा column आहे
|
||||
$headings = array_filter($headings, function ($h) {
|
||||
return strtoupper(trim($h)) !== 'MARK';
|
||||
});
|
||||
}
|
||||
@endphp
|
||||
|
||||
@if(!empty($unmatchedRows))
|
||||
<div class="table-responsive" style="max-height:260px; overflow:auto; border:1px solid #e3e6ef;">
|
||||
<table class="table table-sm table-bordered mb-0" style="font-size:11.5px; min-width:800px;">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Excel Row</th>
|
||||
<th>Mark No</th>
|
||||
@foreach($headings as $head)
|
||||
<th>{{ $head }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($unmatchedRows as $row)
|
||||
<tr>
|
||||
<td>{{ $row['excel_row'] }}</td>
|
||||
<td>{{ $row['mark_no'] }}</td>
|
||||
@foreach($headings as $head)
|
||||
<td>{{ $row['data'][$head] ?? '' }}</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- FORM: unmatched_rows असल्यावर form लपवायचा असेल तर खालील condition ठेवा --}}
|
||||
@if (!session('unmatched_rows'))
|
||||
<form action="{{ route('containers.store') }}" method="POST" enctype="multipart/form-data" class="mt-3">
|
||||
@csrf
|
||||
|
||||
<div class="row g-3">
|
||||
{{-- Container Name --}}
|
||||
<div class="col-md-6">
|
||||
<label class="cm-form-label">Container Name</label>
|
||||
<input type="text"
|
||||
name="container_name"
|
||||
class="form-control cm-form-control"
|
||||
value="{{ old('container_name') }}"
|
||||
placeholder="Enter container name">
|
||||
</div>
|
||||
|
||||
{{-- Container Number --}}
|
||||
<div class="col-md-6">
|
||||
<label class="cm-form-label">Container Number</label>
|
||||
<input type="text"
|
||||
name="container_number"
|
||||
class="form-control cm-form-control"
|
||||
value="{{ old('container_number') }}"
|
||||
placeholder="Enter container number">
|
||||
</div>
|
||||
|
||||
{{-- Container Date --}}
|
||||
<div class="col-md-6">
|
||||
<label class="cm-form-label">Container Date</label>
|
||||
<input type="date"
|
||||
name="container_date"
|
||||
class="form-control cm-form-control"
|
||||
value="{{ old('container_date') }}">
|
||||
</div>
|
||||
|
||||
{{-- Excel File --}}
|
||||
<div class="col-md-6">
|
||||
<label class="cm-form-label">Loading List Excel</label>
|
||||
<input type="file"
|
||||
name="excel_file"
|
||||
class="form-control cm-form-control"
|
||||
accept=".xls,.xlsx">
|
||||
<div class="cm-help-text">
|
||||
Upload Kent loading list Excel file (.xls / .xlsx).
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary cm-btn-primary">
|
||||
Save Container
|
||||
</button>
|
||||
<a href="{{ route('containers.index') }}" class="btn btn-outline-secondary cm-btn-secondary">
|
||||
Cancel
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
291
resources/views/admin/container_show.blade.php
Normal file
291
resources/views/admin/container_show.blade.php
Normal file
@@ -0,0 +1,291 @@
|
||||
@extends('admin.layouts.app')
|
||||
|
||||
@section('page-title', 'Container Details')
|
||||
|
||||
@section('content')
|
||||
<style>
|
||||
.cm-detail-wrapper {
|
||||
padding: 10px 0 20px 0;
|
||||
}
|
||||
.cm-detail-header-card {
|
||||
border-radius: 14px;
|
||||
border: none;
|
||||
margin-bottom: 18px;
|
||||
background: linear-gradient(90deg,#4c6fff,#8e54e9);
|
||||
box-shadow: 0 6px 18px rgba(15,35,52,0.18);
|
||||
color:#ffffff;
|
||||
}
|
||||
.cm-detail-header-card .card-body {
|
||||
padding: 14px 18px;
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
align-items:center;
|
||||
gap:10px;
|
||||
}
|
||||
.cm-detail-title {
|
||||
margin:0;
|
||||
font-size:20px;
|
||||
font-weight:600;
|
||||
}
|
||||
.cm-detail-sub {
|
||||
font-size:12px;
|
||||
opacity:0.9;
|
||||
}
|
||||
.cm-detail-main-card {
|
||||
border-radius:14px;
|
||||
border:none;
|
||||
box-shadow:0 6px 18px rgba(15,35,52,0.12);
|
||||
overflow:hidden;
|
||||
}
|
||||
.cm-detail-main-card .card-header {
|
||||
background:#ffffff;
|
||||
border-bottom:1px solid #edf0f5;
|
||||
padding:10px 18px;
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
align-items:center;
|
||||
gap:10px;
|
||||
}
|
||||
.cm-detail-main-card .card-header h5 {
|
||||
margin:0;
|
||||
font-size:16px;
|
||||
font-weight:600;
|
||||
}
|
||||
.cm-info-label {
|
||||
font-size:12px;
|
||||
color:#6c757d;
|
||||
font-weight:500;
|
||||
}
|
||||
.cm-info-value {
|
||||
font-size:13px;
|
||||
font-weight:500;
|
||||
color:#343a40;
|
||||
}
|
||||
.cm-table-wrapper {
|
||||
position:relative;
|
||||
max-height: 520px;
|
||||
overflow:auto;
|
||||
border-top:1px solid #edf0f5;
|
||||
}
|
||||
.cm-table {
|
||||
font-size:11.5px;
|
||||
min-width: 1100px;
|
||||
}
|
||||
.cm-table thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
background: #fff7e0;
|
||||
color:#495057;
|
||||
font-weight:600;
|
||||
border-bottom:1px solid #e0d2a4;
|
||||
white-space:nowrap;
|
||||
}
|
||||
.cm-table tbody tr:nth-child(even) {
|
||||
background:#fafbff;
|
||||
}
|
||||
.cm-table tbody tr:hover {
|
||||
background:#e9f3ff;
|
||||
}
|
||||
.cm-table td,
|
||||
.cm-table th {
|
||||
padding:4px 6px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.cm-table td {
|
||||
white-space:nowrap;
|
||||
}
|
||||
.cm-table-caption {
|
||||
font-size:11px;
|
||||
color:#868e96;
|
||||
padding:6px 18px 0 18px;
|
||||
}
|
||||
.cm-filter-bar {
|
||||
padding:8px 18px 0 18px;
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
align-items:center;
|
||||
gap:10px;
|
||||
flex-wrap:wrap;
|
||||
}
|
||||
.cm-filter-input {
|
||||
max-width:240px;
|
||||
font-size:12px;
|
||||
border-radius:20px;
|
||||
padding:6px 10px;
|
||||
}
|
||||
.cm-edit-save-btn {
|
||||
font-size:12px;
|
||||
border-radius:20px;
|
||||
padding:6px 14px;
|
||||
}
|
||||
.cm-cell-input {
|
||||
width: 140px;
|
||||
min-width: 120px;
|
||||
max-width: 220px;
|
||||
font-size:11px;
|
||||
padding:3px 4px;
|
||||
height: 26px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.cm-detail-header-card .card-body {
|
||||
flex-direction:column;
|
||||
align-items:flex-start;
|
||||
}
|
||||
.cm-table-wrapper {
|
||||
max-height:400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid cm-detail-wrapper">
|
||||
|
||||
{{-- TOP GRADIENT HEADER --}}
|
||||
<div class="card cm-detail-header-card">
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<h4 class="cm-detail-title">
|
||||
Container: {{ $container->container_number }}
|
||||
</h4>
|
||||
<div class="cm-detail-sub">
|
||||
Edit loading list directly – scroll horizontally and vertically like Excel.
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{ route('containers.index') }}" class="btn btn-light btn-sm">
|
||||
← Back to list
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- MAIN CARD --}}
|
||||
<div class="card cm-detail-main-card">
|
||||
<div class="card-header">
|
||||
<h5>Container Information</h5>
|
||||
|
||||
@if(!$container->rows->isEmpty())
|
||||
{{-- Save button (submits form below) --}}
|
||||
<button type="submit"
|
||||
form="cm-edit-rows-form"
|
||||
class="btn btn-primary cm-edit-save-btn">
|
||||
💾 Save Changes
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="card-body pb-0">
|
||||
{{-- BASIC INFO --}}
|
||||
<div class="row g-3 mb-2">
|
||||
<div class="col-md-4">
|
||||
<div class="cm-info-label">Container</div>
|
||||
<div class="cm-info-value">{{ $container->container_name }}</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="cm-info-label">Date</div>
|
||||
<div class="cm-info-value">
|
||||
{{ $container->container_date?->format('d-m-Y') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="cm-info-label">Excel File</div>
|
||||
@if($container->excel_file)
|
||||
<div class="cm-info-value">
|
||||
<a href="{{ \Illuminate\Support\Facades\Storage::url($container->excel_file) }}"
|
||||
target="_blank">
|
||||
Download / View Excel
|
||||
</a>
|
||||
</div>
|
||||
@else
|
||||
<div class="cm-info-value text-muted">Not uploaded</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($container->rows->isEmpty())
|
||||
<div class="p-3">
|
||||
<p class="mb-0">No entries found for this container.</p>
|
||||
</div>
|
||||
@else
|
||||
@php
|
||||
// सर्व headings collect
|
||||
$allHeadings = [];
|
||||
foreach ($container->rows as $row) {
|
||||
if (is_array($row->data)) {
|
||||
$allHeadings = array_unique(array_merge($allHeadings, array_keys($row->data)));
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
|
||||
{{-- FILTER BAR --}}
|
||||
<div class="cm-filter-bar">
|
||||
<div class="cm-table-caption">
|
||||
Total rows: {{ $container->rows->count() }} • Type to filter rows, edit cells then click "Save Changes".
|
||||
</div>
|
||||
<input type="text" id="cmRowSearch" class="form-control cm-filter-input"
|
||||
placeholder="Quick search in table..." onkeyup="cmFilterRows()">
|
||||
</div>
|
||||
|
||||
{{-- EDITABLE TABLE FORM --}}
|
||||
<form id="cm-edit-rows-form"
|
||||
action="{{ route('containers.rows.update', $container->id) }}"
|
||||
method="POST">
|
||||
@csrf
|
||||
|
||||
<div class="cm-table-wrapper mt-1">
|
||||
<table class="table table-bordered table-hover cm-table" id="cmExcelTable">
|
||||
<thead>
|
||||
<tr>
|
||||
@foreach($allHeadings as $heading)
|
||||
<th>{{ $heading }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($container->rows as $row)
|
||||
<tr>
|
||||
@foreach($allHeadings as $heading)
|
||||
@php
|
||||
$value = $row->data[$heading] ?? '';
|
||||
@endphp
|
||||
<td>
|
||||
<input type="text"
|
||||
class="form-control form-control-sm cm-cell-input"
|
||||
name="rows[{{ $row->id }}][{{ $heading }}]"
|
||||
value="{{ $value }}">
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- SIMPLE FRONT‑END SEARCH --}}
|
||||
<script>
|
||||
function cmFilterRows() {
|
||||
const input = document.getElementById('cmRowSearch');
|
||||
if (!input) return;
|
||||
const filter = input.value.toLowerCase();
|
||||
const table = document.getElementById('cmExcelTable');
|
||||
if (!table) return;
|
||||
|
||||
const rows = table.getElementsByTagName('tr');
|
||||
for (let i = 1; i < rows.length; i++) { // skip header
|
||||
const cells = rows[i].getElementsByTagName('td');
|
||||
let match = false;
|
||||
for (let j = 0; j < cells.length; j++) {
|
||||
const txt = cells[j].textContent || cells[j].innerText;
|
||||
if (txt.toLowerCase().indexOf(filter) > -1) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rows[i].style.display = match ? '' : 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>Admin Panel</title>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
|
||||
<!-- ✅ CRITICAL: CSRF Token for Echo -->
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<title>@yield('page-title', 'Admin Panel')</title>
|
||||
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
|
||||
<style>
|
||||
body {
|
||||
@@ -20,7 +28,6 @@
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* ✨ Sidebar Glass + Animated Highlight Effect */
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
height: 100vh;
|
||||
@@ -39,7 +46,6 @@
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Sidebar collapsed state */
|
||||
.sidebar.collapsed {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
@@ -62,10 +68,11 @@
|
||||
}
|
||||
|
||||
.sidebar .word {
|
||||
color: #800000; font-size: 13px; line-height: 1.24;
|
||||
color: #800000;
|
||||
font-size: 13px;
|
||||
line-height: 1.24;
|
||||
}
|
||||
|
||||
/* 🔥 Sidebar Links */
|
||||
.sidebar a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -82,7 +89,6 @@
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Background Animation */
|
||||
.sidebar a::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@@ -107,7 +113,6 @@
|
||||
color: #1258e0 !important;
|
||||
}
|
||||
|
||||
/* Icon bounce effect */
|
||||
.sidebar a i {
|
||||
margin-right: 8px;
|
||||
font-size: 1.1rem;
|
||||
@@ -119,7 +124,6 @@
|
||||
color: #1258e0 !important;
|
||||
}
|
||||
|
||||
/* Active link glow effect */
|
||||
.sidebar a.active {
|
||||
background: linear-gradient(90deg, rgba(80,120,255,0.15), rgba(120,180,255,0.2));
|
||||
color: #1258e0 !important;
|
||||
@@ -134,7 +138,6 @@
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
/* Logout Button */
|
||||
.sidebar form button {
|
||||
border-radius: 12px;
|
||||
margin-top: 12px;
|
||||
@@ -148,7 +151,6 @@
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
/* 🧭 Main Content */
|
||||
.main-content {
|
||||
flex-grow: 1;
|
||||
min-height: 100vh;
|
||||
@@ -160,13 +162,11 @@
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Main content when sidebar is collapsed */
|
||||
.main-content.expanded {
|
||||
margin-left: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
/* Header hamburger button */
|
||||
.header-toggle {
|
||||
background: transparent;
|
||||
border: none;
|
||||
@@ -220,94 +220,109 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<img src="{{ asset('images/kent_logo2.png') }}" alt="Kent Logo">
|
||||
<div class="word"><strong>KENT</strong><br /><small>International Pvt. Ltd.</small></div>
|
||||
<div class="word">
|
||||
<strong>KENT</strong><br />
|
||||
<small>International Pvt. Ltd.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Dashboard (requires order.view) --}}
|
||||
@can('order.view')
|
||||
<a href="{{ route('admin.dashboard') }}" class="{{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
|
||||
<i class="bi bi-house"></i> Dashboard
|
||||
</a>
|
||||
<a href="{{ route('admin.dashboard') }}" class="{{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
|
||||
<i class="bi bi-house"></i> Dashboard
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
<!--
|
||||
{{-- Shipments --}}
|
||||
@can('shipment.view')
|
||||
<a href="{{ route('admin.shipments') }}" class="{{ request()->routeIs('admin.shipments') ? 'active' : '' }}">
|
||||
<i class="bi bi-truck"></i> Shipments
|
||||
</a>
|
||||
<a href="{{ route('admin.shipments') }}" class="{{ request()->routeIs('admin.shipments') ? 'active' : '' }}">
|
||||
<i class="bi bi-truck"></i> Shipments
|
||||
</a>
|
||||
@endcan -->
|
||||
|
||||
{{-- Container – NEW MENU --}}
|
||||
@can('container.view')
|
||||
<a href="{{ route('containers.index') }}" class="{{ request()->routeIs('containers.*') ? 'active' : '' }}">
|
||||
<i class="fa-solid fa-box"></i> Container
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Invoice --}}
|
||||
@can('invoice.view')
|
||||
<a href="{{ route('admin.invoices.index') }}" class="{{ request()->routeIs('admin.invoices.index') ? 'active' : '' }}">
|
||||
<i class="bi bi-receipt"></i> Invoice
|
||||
</a>
|
||||
<a href="{{ route('admin.invoices.index') }}" class="{{ request()->routeIs('admin.invoices.index') ? 'active' : '' }}">
|
||||
<i class="bi bi-receipt"></i> Invoice
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Customers --}}
|
||||
@can('customer.view')
|
||||
<a href="{{ route('admin.customers.index') }}" class="{{ request()->routeIs('admin.customers.index') ? 'active' : '' }}">
|
||||
<i class="bi bi-people"></i> Customers
|
||||
</a>
|
||||
<a href="{{ route('admin.customers.index') }}" class="{{ request()->routeIs('admin.customers.index') ? 'active' : '' }}">
|
||||
<i class="bi bi-people"></i> Customers
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Reports --}}
|
||||
@can('report.view')
|
||||
<a href="{{ route('admin.reports') }}" class="{{ request()->routeIs('admin.reports') ? 'active' : '' }}">
|
||||
<i class="bi bi-graph-up"></i> Reports
|
||||
</a>
|
||||
<a href="{{ route('admin.reports') }}" class="{{ request()->routeIs('admin.reports') ? 'active' : '' }}">
|
||||
<i class="bi bi-graph-up"></i> Reports
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Chat Support (NO PERMISSION REQUIRED) --}}
|
||||
<a href="{{ route('admin.chat_support') }}" class="{{ request()->routeIs('admin.chat_support') ? 'active' : '' }}">
|
||||
<i class="bi bi-chat-dots"></i> Chat Support
|
||||
</a>
|
||||
|
||||
{{-- Chat Support --}}
|
||||
@can('chat_support.view')
|
||||
<a href="{{ route('admin.chat_support') }}" class="{{ request()->routeIs('admin.chat_support') ? 'active' : '' }}">
|
||||
<i class="bi bi-chat-dots"></i> Chat Support
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Orders --}}
|
||||
@can('orders.view')
|
||||
<a href="{{ route('admin.orders') }}" class="{{ request()->routeIs('admin.orders') ? 'active' : '' }}">
|
||||
<i class="bi bi-bag"></i> Orders
|
||||
</a>
|
||||
<a href="{{ route('admin.orders') }}" class="{{ request()->routeIs('admin.orders') ? 'active' : '' }}">
|
||||
<i class="bi bi-bag"></i> Orders
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Requests --}}
|
||||
@can('request.view')
|
||||
<a href="{{ route('admin.requests') }}" class="{{ request()->routeIs('admin.requests') ? 'active' : '' }}">
|
||||
<i class="bi bi-envelope"></i> Requests
|
||||
</a>
|
||||
<a href="{{ route('admin.requests') }}" class="{{ request()->routeIs('admin.requests') ? 'active' : '' }}">
|
||||
<i class="bi bi-envelope"></i> Requests
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Profile Update Requests --}}
|
||||
@can('request.update_profile')
|
||||
<a href="{{ route('admin.profile.requests') }}">
|
||||
<i class="bi bi-person-lines-fill"></i> Profile Update Requests
|
||||
</a>
|
||||
<a href="{{ route('admin.profile.requests') }}" class="{{ request()->routeIs('admin.profile.requests') ? 'active' : '' }}">
|
||||
<i class="bi bi-person-lines-fill"></i> Profile Update Requests
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Staff (NO PERMISSION REQUIRED) --}}
|
||||
<a href="{{ route('admin.staff.index') }}" class="{{ request()->routeIs('admin.staff.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-person-badge"></i> Staff
|
||||
</a>
|
||||
{{-- Staff --}}
|
||||
@can('staff.view')
|
||||
<a href="{{ route('admin.staff.index') }}" class="{{ request()->routeIs('admin.staff.*') ? 'active' : '' }}">
|
||||
<i class="bi bi-person-badge"></i> Staff
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Account Section --}}
|
||||
@can('account.view')
|
||||
<a href="{{ route('admin.account') }}" class="{{ request()->routeIs('admin.account') ? 'active' : '' }}">
|
||||
<i class="bi bi-gear"></i> Account
|
||||
</a>
|
||||
<a href="{{ route('admin.account') }}" class="{{ request()->routeIs('admin.account') ? 'active' : '' }}">
|
||||
<i class="bi bi-gear"></i> Account
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
{{-- Mark List --}}
|
||||
@can('mark_list.view')
|
||||
<a href="{{ route('admin.marklist.index') }}" class="{{ request()->routeIs('admin.marklist.index') ? 'active' : '' }}">
|
||||
<i class="bi bi-list-check"></i> Mark List
|
||||
</a>
|
||||
<a href="{{ route('admin.marklist.index') }}" class="{{ request()->routeIs('admin.marklist.index') ? 'active' : '' }}">
|
||||
<i class="bi bi-list-check"></i> Mark List
|
||||
</a>
|
||||
@endcan
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
@@ -325,44 +340,53 @@
|
||||
<div class="dropdown">
|
||||
<a href="#" class="d-flex align-items-center text-decoration-none dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<img src="https://i.pravatar.cc/40" class="rounded-circle me-2" width="35" height="35">
|
||||
<span class="dropdown-user-profile-name">{{ Auth::guard('admin')->user()->name ?? 'User' }}</span>
|
||||
<span class="dropdown-user-profile-name">
|
||||
{{ auth('admin')->user()->name ?? 'User' }}
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="{{ route('admin.profile') }}"><i class="bi bi-person-circle me-2"></i>Profile</a></li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ route('admin.profile') }}">
|
||||
<i class="bi bi-person-circle me-2"></i>Profile
|
||||
</a>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<form method="POST" action="{{ route('admin.logout') }}">
|
||||
@csrf
|
||||
<button class="dropdown-item" type="submit"><i class="bi bi-box-arrow-right me-2"></i>Logout</button>
|
||||
<button class="dropdown-item" type="submit">
|
||||
<i class="bi bi-box-arrow-right me-2"></i>Logout
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="content-wrapper">
|
||||
@yield('content')
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
@vite(['resources/js/app.js'])
|
||||
@yield('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const headerToggle = document.getElementById('headerToggle');
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
const mainContent = document.querySelector('.main-content');
|
||||
|
||||
// Function to toggle sidebar
|
||||
function toggleSidebar() {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
mainContent.classList.toggle('expanded');
|
||||
}
|
||||
|
||||
// Header toggle button click event
|
||||
if (headerToggle) {
|
||||
headerToggle.addEventListener('click', toggleSidebar);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Professional Invoice</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary: #2c3e50;
|
||||
@@ -19,48 +21,48 @@
|
||||
--border-radius: 8px;
|
||||
--box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: #f5f7fa;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
.invoice-container {
|
||||
max-width: 1200px;
|
||||
margin: 2rem auto;
|
||||
background: white;
|
||||
background: #ffffff;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.invoice-header {
|
||||
background: white;
|
||||
background: #ffffff;
|
||||
padding: 1.5rem 2rem;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
|
||||
.invoice-title {
|
||||
font-weight: 700;
|
||||
font-size: 1.8rem;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
|
||||
.status-badge {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
.id-container {
|
||||
margin-bottom: 1rem; /* Reduced from 1.5rem */
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.id-box {
|
||||
background: white;
|
||||
background: #ffffff;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 1rem;
|
||||
border: 1px solid #e9ecef;
|
||||
@@ -68,24 +70,20 @@
|
||||
transition: all 0.3s ease;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.id-box:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
|
||||
.id-box-primary {
|
||||
border-left: 4px solid var(--secondary);
|
||||
}
|
||||
|
||||
|
||||
.id-box-secondary {
|
||||
border-left: 4px solid var(--success);
|
||||
}
|
||||
|
||||
.id-box-accent {
|
||||
border-left: 4px solid var(--warning);
|
||||
}
|
||||
|
||||
|
||||
.id-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
@@ -93,25 +91,20 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 0.5rem; /* Reduced from 0.75rem */
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.id-icon-primary {
|
||||
background: rgba(52, 152, 219, 0.1);
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
|
||||
.id-icon-secondary {
|
||||
background: rgba(39, 174, 96, 0.1);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.id-icon-accent {
|
||||
background: rgba(243, 156, 18, 0.1);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
|
||||
.id-label {
|
||||
font-size: 0.75rem;
|
||||
color: #6c757d;
|
||||
@@ -120,31 +113,31 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
|
||||
.id-value {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
.date-container {
|
||||
background: white;
|
||||
background: #ffffff;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 1rem; /* Reduced from 1.25rem */
|
||||
margin-bottom: 1rem; /* Reduced from 1.5rem */
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid #e9ecef;
|
||||
box-shadow: var(--box-shadow);
|
||||
}
|
||||
|
||||
|
||||
.date-card {
|
||||
text-align: center;
|
||||
padding: 0.75rem;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid rgba(0,0,0,0.05);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
|
||||
.date-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -152,12 +145,12 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 0.5rem; /* Reduced from 0.75rem */
|
||||
margin: 0 auto 0.5rem;
|
||||
background: var(--secondary);
|
||||
color: white;
|
||||
color: #ffffff;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.date-label {
|
||||
font-size: 0.8rem;
|
||||
color: #6c757d;
|
||||
@@ -166,24 +159,24 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
|
||||
.date-value {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
padding: 0.5rem;
|
||||
background: white;
|
||||
background: #ffffff;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
|
||||
.date-connector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.date-connector i {
|
||||
background: var(--light);
|
||||
padding: 10px;
|
||||
@@ -191,14 +184,14 @@
|
||||
color: var(--secondary);
|
||||
border: 2px solid #e9ecef;
|
||||
}
|
||||
|
||||
|
||||
.card {
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: var(--border-radius);
|
||||
margin-bottom: 1rem; /* Reduced from 1.5rem */
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: var(--box-shadow);
|
||||
}
|
||||
|
||||
|
||||
.card-header {
|
||||
background: var(--light);
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
@@ -206,16 +199,16 @@
|
||||
font-weight: 600;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
|
||||
.table {
|
||||
margin-bottom: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
|
||||
.table > :not(caption) > * > * {
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
|
||||
.table thead th {
|
||||
background-color: var(--light);
|
||||
color: var(--primary);
|
||||
@@ -223,75 +216,63 @@
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
|
||||
.table tbody tr:hover {
|
||||
background-color: rgba(52, 152, 219, 0.03);
|
||||
}
|
||||
|
||||
|
||||
.summary-card {
|
||||
background: var(--light);
|
||||
border-left: 4px solid var(--secondary);
|
||||
}
|
||||
|
||||
|
||||
.summary-header {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.amount-row {
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
padding: 0.75rem 0;
|
||||
}
|
||||
|
||||
.total-row {
|
||||
border-top: 2px solid #dee2e6;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
|
||||
|
||||
.text-success {
|
||||
color: var(--success) !important;
|
||||
}
|
||||
|
||||
|
||||
.text-danger {
|
||||
color: var(--danger) !important;
|
||||
}
|
||||
|
||||
|
||||
.badge {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.35rem 0.65rem;
|
||||
}
|
||||
|
||||
/* COMPACT HEADER STYLES */
|
||||
|
||||
.compact-header {
|
||||
margin-bottom: 0.75rem; /* Reduced from default */
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
.compact-header .invoice-title {
|
||||
margin-bottom: 0.25rem; /* Reduced gap */
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
|
||||
.compact-header .status-badge {
|
||||
margin-top: 0.25rem; /* Reduced gap */
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.invoice-container {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.date-connector {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
|
||||
.table-responsive {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
.id-box {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -299,308 +280,342 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="invoice-container">
|
||||
<div class="p-4">
|
||||
<!-- ============================
|
||||
INVOICE HEADER - COMPACT
|
||||
============================ -->
|
||||
@php
|
||||
<div class="invoice-container">
|
||||
<div class="p-4">
|
||||
@php
|
||||
$showActions = $showActions ?? true;
|
||||
@endphp
|
||||
@endphp
|
||||
|
||||
<div class="compact-header">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="invoice-title mb-1">
|
||||
<i class="fas fa-file-invoice me-2"></i> INVOICE
|
||||
</h2>
|
||||
<h4 class="fw-bold text-dark mb-0">{{ $invoice->invoice_number }}</h4>
|
||||
{{-- HEADER --}}
|
||||
<div class="compact-header">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="invoice-title mb-1">
|
||||
<i class="fas fa-file-invoice me-2"></i> INVOICE
|
||||
</h2>
|
||||
<h4 class="fw-bold text-dark mb-0">{{ $invoice->invoice_number }}</h4>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<span class="status-badge
|
||||
@if($invoice->status == 'paid') bg-success
|
||||
@elseif($invoice->status == 'overdue') bg-danger
|
||||
@elseif($invoice->status == 'pending') bg-warning text-dark
|
||||
@else bg-secondary @endif">
|
||||
<i class="fas
|
||||
@if($invoice->status == 'paid') fa-check-circle
|
||||
@elseif($invoice->status == 'overdue') fa-exclamation-circle
|
||||
@elseif($invoice->status == 'pending') fa-clock
|
||||
@else fa-question-circle @endif me-1"></i>
|
||||
{{ ucfirst($invoice->status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ID BOXES: INVOICE + CONTAINER --}}
|
||||
<div class="id-container">
|
||||
<div class="row">
|
||||
{{-- Invoice ID Box --}}
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="id-box id-box-primary">
|
||||
<div class="id-icon id-icon-primary">
|
||||
<i class="fas fa-receipt"></i>
|
||||
</div>
|
||||
<div class="id-label">Invoice ID</div>
|
||||
<div class="id-value">{{ $invoice->invoice_number }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 text-end">
|
||||
<span class="status-badge
|
||||
@if($invoice->status=='paid') bg-success
|
||||
@elseif($invoice->status=='overdue') bg-danger
|
||||
@elseif($invoice->status=='pending') bg-warning text-dark
|
||||
@else bg-secondary @endif">
|
||||
<i class="fas
|
||||
@if($invoice->status=='paid') fa-check-circle
|
||||
@elseif($invoice->status=='overdue') fa-exclamation-circle
|
||||
@elseif($invoice->status=='pending') fa-clock
|
||||
@else fa-question-circle @endif me-1"></i>
|
||||
{{ ucfirst($invoice->status) }}
|
||||
</span>
|
||||
{{-- Container ID Box --}}
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="id-box id-box-secondary">
|
||||
<div class="id-icon id-icon-secondary">
|
||||
<i class="fas fa-box"></i>
|
||||
</div>
|
||||
<div class="id-label">Container ID</div>
|
||||
<div class="id-value">
|
||||
@if($invoice->container && $invoice->container->container_number)
|
||||
{{ $invoice->container->container_number }}
|
||||
@elseif($invoice->container_id)
|
||||
{{ $invoice->container_id }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{-- DATES --}}
|
||||
<div class="date-container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-5">
|
||||
<div class="date-card">
|
||||
<div class="date-icon">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</div>
|
||||
<div class="date-label">INVOICE DATE</div>
|
||||
<div class="date-value">
|
||||
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="date-connector">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="date-card">
|
||||
<div class="date-icon">
|
||||
<i class="fas fa-clock"></i>
|
||||
</div>
|
||||
<div class="date-label">DUE DATE</div>
|
||||
<div class="date-value @if($invoice->status == 'overdue') text-danger @endif">
|
||||
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Three ID Boxes in One Row -->
|
||||
<div class="id-container">
|
||||
{{-- CUSTOMER DETAILS --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-user me-2"></i> Customer Details
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<!-- Invoice ID Box -->
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="id-box id-box-primary">
|
||||
<div class="id-icon id-icon-primary">
|
||||
<i class="fas fa-receipt"></i>
|
||||
</div>
|
||||
<div class="id-label">Invoice ID</div>
|
||||
<div class="id-value">{{ $invoice->invoice_number }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order ID Box -->
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="id-box id-box-secondary">
|
||||
<div class="id-icon id-icon-secondary">
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
</div>
|
||||
<div class="id-label">Order ID</div>
|
||||
<div class="id-value">
|
||||
@if($invoice->order && $invoice->order->order_id)
|
||||
{{ $invoice->order->order_id }}
|
||||
@elseif($invoice->order_id)
|
||||
{{ $invoice->order_id }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shipment ID Box -->
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="id-box id-box-accent">
|
||||
<div class="id-icon id-icon-accent">
|
||||
<i class="fas fa-shipping-fast"></i>
|
||||
</div>
|
||||
<div class="id-label">Shipment ID</div>
|
||||
<div class="id-value">
|
||||
@php
|
||||
$shipmentId = 'N/A';
|
||||
// Try multiple ways to get shipment ID
|
||||
if($invoice->shipment && $invoice->shipment->shipment_id) {
|
||||
$shipmentId = $invoice->shipment->shipment_id;
|
||||
} elseif($invoice->shipment_id) {
|
||||
$shipmentId = $invoice->shipment_id;
|
||||
} elseif(isset($shipment) && $shipment && $shipment->shipment_id) {
|
||||
$shipmentId = $shipment->shipment_id;
|
||||
}
|
||||
@endphp
|
||||
{{ $shipmentId }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
DATES SECTION
|
||||
============================ -->
|
||||
<div class="date-container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-5">
|
||||
<div class="date-card">
|
||||
<div class="date-icon">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</div>
|
||||
<div class="date-label">INVOICE DATE</div>
|
||||
<div class="date-value">{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="date-connector">
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<div class="date-card">
|
||||
<div class="date-icon">
|
||||
<i class="fas fa-clock"></i>
|
||||
</div>
|
||||
<div class="date-label">DUE DATE</div>
|
||||
<div class="date-value @if($invoice->status == 'overdue') text-danger @endif">
|
||||
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
CUSTOMER DETAILS
|
||||
============================ -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-user me-2"></i> Customer Details
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="fw-bold text-primary mb-1">{{ $invoice->customer_name }}</h6>
|
||||
@if($invoice->company_name)
|
||||
<div class="col-md-6">
|
||||
<h6 class="fw-bold text-primary mb-1">{{ $invoice->customer_name }}</h6>
|
||||
@if($invoice->company_name)
|
||||
<p class="mb-1">
|
||||
<strong>Company:</strong> {{ $invoice->company_name }}
|
||||
</p>
|
||||
@endif
|
||||
<p class="mb-1">
|
||||
<strong>Mobile:</strong> {{ $invoice->customer_mobile }}
|
||||
</p>
|
||||
<p class="mb-1">
|
||||
<strong>Email:</strong> {{ $invoice->customer_email }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="mb-1">
|
||||
<strong>Address:</strong><br>
|
||||
{{ $invoice->customer_address }}
|
||||
</p>
|
||||
<p class="mb-1">
|
||||
<strong>Pincode:</strong> {{ $invoice->pincode }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
<p class="mb-1">
|
||||
<strong>Mobile:</strong> {{ $invoice->customer_mobile }}
|
||||
</p>
|
||||
<p class="mb-1">
|
||||
<strong>Email:</strong> {{ $invoice->customer_email }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="mb-1">
|
||||
<strong>Address:</strong><br>
|
||||
{{ $invoice->customer_address }}
|
||||
</p>
|
||||
<p class="mb-1">
|
||||
<strong>Pincode:</strong> {{ $invoice->pincode }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
INVOICE ITEMS
|
||||
============================ -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-list me-2"></i> Invoice Items
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="text-center">#</th>
|
||||
<th>Description</th>
|
||||
<th class="text-center">CTN</th>
|
||||
<th class="text-center">QTY</th>
|
||||
<th class="text-center">TTL/QTY</th>
|
||||
<th class="text-center">Unit</th>
|
||||
<th class="text-center">Price</th>
|
||||
<th class="text-center">TTL Amount</th>
|
||||
<th class="text-center">CBM</th>
|
||||
<th class="text-center">TTL CBM</th>
|
||||
<th class="text-center">KG</th>
|
||||
<th class="text-center">TTL KG</th>
|
||||
<th class="text-center">Shop No</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($invoice->items as $i => $item)
|
||||
<tr>
|
||||
<td class="text-center fw-bold text-muted">{{ $i+1 }}</td>
|
||||
<td class="fw-semibold">{{ $item->description }}</td>
|
||||
<td class="text-center">{{ $item->ctn }}</td>
|
||||
<td class="text-center">{{ $item->qty }}</td>
|
||||
<td class="text-center fw-bold">{{ $item->ttl_qty }}</td>
|
||||
<td class="text-center">{{ $item->unit }}</td>
|
||||
<td class="text-center text-success fw-bold">₹{{ number_format($item->price,2) }}</td>
|
||||
<td class="text-center text-primary fw-bold">₹{{ number_format($item->ttl_amount,2) }}</td>
|
||||
<td class="text-center">{{ $item->cbm }}</td>
|
||||
<td class="text-center">{{ $item->ttl_cbm }}</td>
|
||||
<td class="text-center">{{ $item->kg }}</td>
|
||||
<td class="text-center">{{ $item->ttl_kg }}</td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-light text-dark border">{{ $item->shop_no }}</span>
|
||||
{{-- INVOICE ITEMS (EDITABLE WHEN EMBEDDED) --}}
|
||||
@php
|
||||
$isEmbedded = isset($embedded) && $embedded;
|
||||
@endphp
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-list me-2"></i> Invoice Items
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
|
||||
@if($isEmbedded)
|
||||
<form action="{{ route('admin.invoices.items.update', $invoice->id) }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="text-center">#</th>
|
||||
<th>Description</th>
|
||||
<th class="text-center">CTN</th>
|
||||
<th class="text-center">QTY</th>
|
||||
<th class="text-center">TTL/QTY</th>
|
||||
<th class="text-center">Unit</th>
|
||||
<th class="text-center">Price</th>
|
||||
<th class="text-center">TTL Amount</th>
|
||||
<th class="text-center">CBM</th>
|
||||
<th class="text-center">TTL CBM</th>
|
||||
<th class="text-center">KG</th>
|
||||
<th class="text-center">TTL KG</th>
|
||||
<th class="text-center">Shop No</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($invoice->items as $i => $item)
|
||||
<tr>
|
||||
<td class="text-center fw-bold text-muted">{{ $i + 1 }}</td>
|
||||
<td class="fw-semibold">{{ $item->description }}</td>
|
||||
<td class="text-center">{{ $item->ctn }}</td>
|
||||
<td class="text-center">{{ $item->qty }}</td>
|
||||
<td class="text-center fw-bold">{{ $item->ttl_qty }}</td>
|
||||
<td class="text-center">{{ $item->unit }}</td>
|
||||
|
||||
@if($isEmbedded)
|
||||
{{-- EDIT MODE (invoice_edit page) --}}
|
||||
<td class="text-center" style="width:120px;">
|
||||
<input type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
name="items[{{ $item->id }}][price]"
|
||||
value="{{ old('items.' . $item->id . '.price', $item->price) }}"
|
||||
class="form-control form-control-sm text-end">
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<td class="text-center" style="width:140px;">
|
||||
<input type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
name="items[{{ $item->id }}][ttl_amount]"
|
||||
value="{{ old('items.' . $item->id . '.ttl_amount', $item->ttl_amount) }}"
|
||||
class="form-control form-control-sm text-end">
|
||||
</td>
|
||||
@else
|
||||
{{-- NORMAL POPUP (READ-ONLY) --}}
|
||||
<td class="text-center text-success fw-bold">
|
||||
₹{{ number_format($item->price, 2) }}
|
||||
</td>
|
||||
<td class="text-center text-primary fw-bold">
|
||||
₹{{ number_format($item->ttl_amount, 2) }}
|
||||
</td>
|
||||
@endif
|
||||
|
||||
<!-- ============================
|
||||
FINAL SUMMARY
|
||||
============================ -->
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-6">
|
||||
<div class="card summary-card">
|
||||
<div class="card-header summary-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-calculator me-2"></i> Final Summary
|
||||
</h6>
|
||||
<td class="text-center">{{ $item->cbm }}</td>
|
||||
<td class="text-center">{{ $item->ttl_cbm }}</td>
|
||||
<td class="text-center">{{ $item->kg }}</td>
|
||||
<td class="text-center">{{ $item->ttl_kg }}</td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-light text-dark border">{{ $item->shop_no }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@if($invoice->items->isEmpty())
|
||||
<tr>
|
||||
<td colspan="13" class="text-center text-muted fw-bold py-3">
|
||||
No invoice items found.
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($isEmbedded)
|
||||
<div class="text-end p-3">
|
||||
<button type="submit" class="btn btn-primary btn-sm">
|
||||
<i class="fas fa-save me-1"></i> Update Items & Recalculate
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- FINAL SUMMARY --}}
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-6">
|
||||
<div class="card summary-card">
|
||||
<div class="card-header summary-header">
|
||||
<h6 class="mb-0 fw-bold">
|
||||
<i class="fas fa-calculator me-2"></i> Final Summary
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">Amount:</span>
|
||||
<span class="fw-bold text-dark">
|
||||
₹{{ number_format($invoice->final_amount, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@if($invoice->tax_type === 'gst')
|
||||
{{-- CGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">Amount:</span>
|
||||
<span class="fw-bold text-dark">₹{{ number_format($invoice->final_amount,2) }}</span>
|
||||
<span class="fw-semibold">
|
||||
CGST ({{ $invoice->cgst_percent ?? ($invoice->gst_percent / 2) }}%):
|
||||
</span>
|
||||
<span class="fw-bold text-danger">
|
||||
₹{{ number_format($invoice->gst_amount / 2, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@if($invoice->tax_type === 'gst')
|
||||
{{-- CGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">CGST ({{ $invoice->cgst_percent ?? ($invoice->gst_percent/2) }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount/2, 2) }}</span>
|
||||
</div>
|
||||
|
||||
{{-- SGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">SGST ({{ $invoice->sgst_percent ?? ($invoice->gst_percent/2) }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount/2, 2) }}</span>
|
||||
</div>
|
||||
|
||||
@elseif($invoice->tax_type === 'igst')
|
||||
{{-- IGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">IGST ({{ $invoice->igst_percent ?? $invoice->gst_percent }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount, 2) }}</span>
|
||||
</div>
|
||||
@else
|
||||
{{-- Default GST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">GST ({{ $invoice->gst_percent }}%):</span>
|
||||
<span class="fw-bold text-danger">₹{{ number_format($invoice->gst_amount, 2) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pt-1">
|
||||
<span class="fw-bold text-dark">Total Payable:</span>
|
||||
<span class="fw-bold text-success">₹{{ number_format($invoice->final_amount_with_gst,2) }}</span>
|
||||
{{-- SGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">
|
||||
SGST ({{ $invoice->sgst_percent ?? ($invoice->gst_percent / 2) }}%):
|
||||
</span>
|
||||
<span class="fw-bold text-danger">
|
||||
₹{{ number_format($invoice->gst_amount / 2, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
@elseif($invoice->tax_type === 'igst')
|
||||
{{-- IGST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">
|
||||
IGST ({{ $invoice->igst_percent ?? $invoice->gst_percent }}%):
|
||||
</span>
|
||||
<span class="fw-bold text-danger">
|
||||
₹{{ number_format($invoice->gst_amount, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
@else
|
||||
{{-- Default GST --}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
|
||||
<span class="fw-semibold">
|
||||
GST ({{ $invoice->gst_percent }}%):
|
||||
</span>
|
||||
<span class="fw-bold text-danger">
|
||||
₹{{ number_format($invoice->gst_amount, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pt-1">
|
||||
<span class="fw-bold text-dark">Total Payable:</span>
|
||||
<span class="fw-bold text-success">
|
||||
₹{{ number_format($invoice->final_amount_with_gst, 2) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================
|
||||
FOOTER — DOWNLOAD & SHARE
|
||||
============================ -->
|
||||
<div class="mt-4 pt-3 border-top text-center">
|
||||
@if($invoice->pdf_path)
|
||||
<a href="{{ asset($invoice->pdf_path) }}" class="btn btn-primary me-2" download>
|
||||
</div>
|
||||
|
||||
{{-- FOOTER ACTIONS --}}
|
||||
<div class="mt-4 pt-3 border-top text-center">
|
||||
@if($invoice->pdf_path && $showActions)
|
||||
<a href="{{ asset($invoice->pdf_path) }}"
|
||||
class="btn btn-primary me-2" download>
|
||||
<i class="fas fa-download me-1"></i> Download PDF
|
||||
</a>
|
||||
|
||||
<button class="btn btn-success" onclick="shareInvoice()">
|
||||
<i class="fas fa-share me-1"></i> Share
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Footer Message -->
|
||||
<div class="mt-4 pt-3 border-top text-center text-muted">
|
||||
<p class="mb-1">Thank you for your business!</p>
|
||||
<p class="mb-0">For any inquiries, contact us at support@Kent Logistic</p>
|
||||
</div>
|
||||
{{-- FOOTER MESSAGE --}}
|
||||
<div class="mt-4 pt-3 border-top text-center text-muted">
|
||||
<p class="mb-1">Thank you for your business!</p>
|
||||
<p class="mb-0">For any inquiries, contact us at support@Kent Logistic</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- ============================
|
||||
SHARE SCRIPT
|
||||
============================ -->
|
||||
<script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
function shareInvoice() {
|
||||
const shareData = {
|
||||
title: "Invoice {{ $invoice->invoice_number }}",
|
||||
@@ -615,6 +630,6 @@
|
||||
alert("Link copied! Sharing not supported on this browser.");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user