Invoice Frontend

This commit is contained in:
Utkarsh Khedkar
2025-11-18 14:35:58 +05:30
parent 56a17cf1e0
commit 837f4fe566
13 changed files with 1695 additions and 303 deletions

180
composer.lock generated
View File

@@ -1054,16 +1054,16 @@
},
{
"name": "laravel/framework",
"version": "v12.37.0",
"version": "v12.38.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "3c3c4ad30f5b528b164a7c09aa4ad03118c4c125"
"reference": "7f3012af6059f5f64a12930701cd8caed6cf7c17"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/3c3c4ad30f5b528b164a7c09aa4ad03118c4c125",
"reference": "3c3c4ad30f5b528b164a7c09aa4ad03118c4c125",
"url": "https://api.github.com/repos/laravel/framework/zipball/7f3012af6059f5f64a12930701cd8caed6cf7c17",
"reference": "7f3012af6059f5f64a12930701cd8caed6cf7c17",
"shasum": ""
},
"require": {
@@ -1181,7 +1181,7 @@
"phpstan/phpstan": "^2.0",
"phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1",
"predis/predis": "^2.3|^3.0",
"resend/resend-php": "^0.10.0",
"resend/resend-php": "^0.10.0|^1.0",
"symfony/cache": "^7.2.0",
"symfony/http-client": "^7.2.0",
"symfony/psr-http-message-bridge": "^7.2.0",
@@ -1215,7 +1215,7 @@
"predis/predis": "Required to use the predis connector (^2.3|^3.0).",
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
"resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).",
"resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0|^1.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^7.2).",
"symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).",
"symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).",
@@ -1269,7 +1269,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-11-04T15:39:33+00:00"
"time": "2025-11-13T02:12:47+00:00"
},
{
"name": "laravel/prompts",
@@ -1721,16 +1721,16 @@
},
{
"name": "league/flysystem",
"version": "3.30.1",
"version": "3.30.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da"
"reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c139fd65c1f796b926f4aec0df37f6caa959a8da",
"reference": "c139fd65c1f796b926f4aec0df37f6caa959a8da",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277",
"reference": "5966a8ba23e62bdb518dd9e0e665c2dbd4b5b277",
"shasum": ""
},
"require": {
@@ -1798,22 +1798,22 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.30.1"
"source": "https://github.com/thephpleague/flysystem/tree/3.30.2"
},
"time": "2025-10-20T15:35:26+00:00"
"time": "2025-11-10T17:13:11+00:00"
},
{
"name": "league/flysystem-local",
"version": "3.30.0",
"version": "3.30.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
"reference": "6691915f77c7fb69adfb87dcd550052dc184ee10"
"reference": "ab4f9d0d672f601b102936aa728801dd1a11968d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10",
"reference": "6691915f77c7fb69adfb87dcd550052dc184ee10",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ab4f9d0d672f601b102936aa728801dd1a11968d",
"reference": "ab4f9d0d672f601b102936aa728801dd1a11968d",
"shasum": ""
},
"require": {
@@ -1847,9 +1847,9 @@
"local"
],
"support": {
"source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0"
"source": "https://github.com/thephpleague/flysystem-local/tree/3.30.2"
},
"time": "2025-05-21T10:34:19+00:00"
"time": "2025-11-10T11:23:37+00:00"
},
{
"name": "league/mime-type-detection",
@@ -3946,16 +3946,16 @@
},
{
"name": "symfony/console",
"version": "v7.3.5",
"version": "v7.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
"reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
"url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
"reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
"shasum": ""
},
"require": {
@@ -4020,7 +4020,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.5"
"source": "https://github.com/symfony/console/tree/v7.3.6"
},
"funding": [
{
@@ -4040,20 +4040,20 @@
"type": "tidelift"
}
],
"time": "2025-10-14T15:46:26+00:00"
"time": "2025-11-04T01:21:42+00:00"
},
{
"name": "symfony/css-selector",
"version": "v7.3.0",
"version": "v7.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2"
"reference": "84321188c4754e64273b46b406081ad9b18e8614"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2",
"reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/84321188c4754e64273b46b406081ad9b18e8614",
"reference": "84321188c4754e64273b46b406081ad9b18e8614",
"shasum": ""
},
"require": {
@@ -4089,7 +4089,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v7.3.0"
"source": "https://github.com/symfony/css-selector/tree/v7.3.6"
},
"funding": [
{
@@ -4100,12 +4100,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-25T14:21:43+00:00"
"time": "2025-10-29T17:24:25+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -4176,16 +4180,16 @@
},
{
"name": "symfony/error-handler",
"version": "v7.3.4",
"version": "v7.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
"reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4"
"reference": "bbe40bfab84323d99dab491b716ff142410a92a8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/99f81bc944ab8e5dae4f21b4ca9972698bbad0e4",
"reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/bbe40bfab84323d99dab491b716ff142410a92a8",
"reference": "bbe40bfab84323d99dab491b716ff142410a92a8",
"shasum": ""
},
"require": {
@@ -4233,7 +4237,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/error-handler/tree/v7.3.4"
"source": "https://github.com/symfony/error-handler/tree/v7.3.6"
},
"funding": [
{
@@ -4253,7 +4257,7 @@
"type": "tidelift"
}
],
"time": "2025-09-11T10:12:26+00:00"
"time": "2025-10-31T19:12:50+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -4485,16 +4489,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v7.3.5",
"version": "v7.3.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/db488a62f98f7a81d5746f05eea63a74e55bb7c4",
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4",
"shasum": ""
},
"require": {
@@ -4544,7 +4548,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v7.3.5"
"source": "https://github.com/symfony/http-foundation/tree/v7.3.7"
},
"funding": [
{
@@ -4564,20 +4568,20 @@
"type": "tidelift"
}
],
"time": "2025-10-24T21:42:11+00:00"
"time": "2025-11-08T16:41:12+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v7.3.5",
"version": "v7.3.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
"reference": "10b8e9b748ea95fa4539c208e2487c435d3c87ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/10b8e9b748ea95fa4539c208e2487c435d3c87ce",
"reference": "10b8e9b748ea95fa4539c208e2487c435d3c87ce",
"shasum": ""
},
"require": {
@@ -4662,7 +4666,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v7.3.5"
"source": "https://github.com/symfony/http-kernel/tree/v7.3.7"
},
"funding": [
{
@@ -4682,7 +4686,7 @@
"type": "tidelift"
}
],
"time": "2025-10-28T10:19:01+00:00"
"time": "2025-11-12T11:38:40+00:00"
},
{
"name": "symfony/mailer",
@@ -5820,16 +5824,16 @@
},
{
"name": "symfony/routing",
"version": "v7.3.4",
"version": "v7.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c"
"reference": "c97abe725f2a1a858deca629a6488c8fc20c3091"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/8dc648e159e9bac02b703b9fbd937f19ba13d07c",
"reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c",
"url": "https://api.github.com/repos/symfony/routing/zipball/c97abe725f2a1a858deca629a6488c8fc20c3091",
"reference": "c97abe725f2a1a858deca629a6488c8fc20c3091",
"shasum": ""
},
"require": {
@@ -5881,7 +5885,7 @@
"url"
],
"support": {
"source": "https://github.com/symfony/routing/tree/v7.3.4"
"source": "https://github.com/symfony/routing/tree/v7.3.6"
},
"funding": [
{
@@ -5901,20 +5905,20 @@
"type": "tidelift"
}
],
"time": "2025-09-11T10:12:26+00:00"
"time": "2025-11-05T07:57:47+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.6.0",
"version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
@@ -5968,7 +5972,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
"source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -5979,12 +5983,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-04-25T09:37:31+00:00"
"time": "2025-07-15T11:30:57+00:00"
},
{
"name": "symfony/string",
@@ -6178,16 +6186,16 @@
},
{
"name": "symfony/translation-contracts",
"version": "v3.6.0",
"version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
"reference": "65a8bc82080447fae78373aa10f8d13b38338977"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977",
"reference": "65a8bc82080447fae78373aa10f8d13b38338977",
"shasum": ""
},
"require": {
@@ -6236,7 +6244,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
"source": "https://github.com/symfony/translation-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -6247,12 +6255,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-27T08:32:26+00:00"
"time": "2025-07-15T13:41:35+00:00"
},
{
"name": "symfony/uid",
@@ -6962,16 +6974,16 @@
},
{
"name": "laravel/sail",
"version": "v1.47.0",
"version": "v1.48.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/sail.git",
"reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2"
"reference": "1bf3b8870b72a258a3b6b5119435835ece522e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sail/zipball/9a11e822238167ad8b791e4ea51155d25cf4d8f2",
"reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2",
"url": "https://api.github.com/repos/laravel/sail/zipball/1bf3b8870b72a258a3b6b5119435835ece522e8a",
"reference": "1bf3b8870b72a258a3b6b5119435835ece522e8a",
"shasum": ""
},
"require": {
@@ -7021,7 +7033,7 @@
"issues": "https://github.com/laravel/sail/issues",
"source": "https://github.com/laravel/sail"
},
"time": "2025-10-28T13:55:29+00:00"
"time": "2025-11-09T14:46:21+00:00"
},
{
"name": "mockery/mockery",
@@ -7660,16 +7672,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.43",
"version": "11.5.44",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c6b89b6cf4324a8b4cb86e1f5dfdd6c9e0371924"
"reference": "c346885c95423eda3f65d85a194aaa24873cda82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c6b89b6cf4324a8b4cb86e1f5dfdd6c9e0371924",
"reference": "c6b89b6cf4324a8b4cb86e1f5dfdd6c9e0371924",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c346885c95423eda3f65d85a194aaa24873cda82",
"reference": "c346885c95423eda3f65d85a194aaa24873cda82",
"shasum": ""
},
"require": {
@@ -7741,7 +7753,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.43"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.44"
},
"funding": [
{
@@ -7765,7 +7777,7 @@
"type": "tidelift"
}
],
"time": "2025-10-30T08:39:39+00:00"
"time": "2025-11-13T07:17:35+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -8883,16 +8895,16 @@
},
{
"name": "theseer/tokenizer",
"version": "1.2.3",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
"reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb",
"shasum": ""
},
"require": {
@@ -8921,7 +8933,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.2.3"
"source": "https://github.com/theseer/tokenizer/tree/1.3.0"
},
"funding": [
{
@@ -8929,7 +8941,7 @@
"type": "github"
}
],
"time": "2024-03-03T12:36:25+00:00"
"time": "2025-11-13T13:44:09+00:00"
}
],
"aliases": [],

View File

@@ -18,3 +18,4 @@ require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$app->handleRequest(Request::capture());

Binary file not shown.

Binary file not shown.

View File

@@ -506,20 +506,6 @@ body, .container-fluid { background: #f4f7fc; }
letter-spacing: 0.5px;
}
#orderDetailsBody {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
#orderDetailsBody > * {
width: 100%;
max-width: 100%;
}
.status-pending { background: #fff3cd; color: #856404; }
.status-completed { background: #d1edff; color: #0c5460; }
.status-processing { background: #d4edda; color: #155724; }
@@ -669,6 +655,65 @@ body, .container-fluid { background: #f4f7fc; }
}
}
/* NEW: Sticky customer info header for order details */
.sticky-customer-header {
position: sticky;
top: 0;
background: white;
z-index: 100;
padding: 20px;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-left: 5px solid #667eea;
}
.customer-info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
}
.customer-info-item {
display: flex;
flex-direction: column;
}
.customer-info-label {
font-size: 0.8rem;
color: #6c757d;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 4px;
}
.customer-info-value {
font-size: 1rem;
font-weight: 600;
color: #2c3e50;
word-break: break-word;
}
/* Scrollable table container */
.scrollable-table-container {
max-height: 400px;
overflow-y: auto;
border: 1px solid #e9ecef;
border-radius: 12px;
margin-top: 20px;
}
.scrollable-table-container .modern-table {
margin-bottom: 0;
}
.scrollable-table-container .modern-table thead th {
position: sticky;
top: 0;
z-index: 10;
}
</style>
<div class="container-fluid py-3">
@@ -1082,6 +1127,8 @@ document.addEventListener('DOMContentLoaded', function () {
});
});
</script>

View File

@@ -3,107 +3,877 @@
@section('page-title', 'Invoice List')
@section('content')
<style>
/*Remove horizontal scroll bar*/
html, body {
overflow-x: hidden !important;
}
<div class="card shadow-sm">
<div class="card-header bg-light">
<h4 class="mb-0">All Invoices</h4>
</div>
/* Invoice Management Styles */
.invoice-management-box {
background: #fff;
border-radius: 17px;
box-shadow: 0 7px 38px #dde3fa77, 0 2px 9px #e5e7ff80;
margin-bottom: 33px;
margin-top: 10px;
}
<div class="card-body table-responsive">
<table class="table table-bordered table-striped align-middle text-center">
<thead class="table-light">
<tr>
<th>#</th>
<th>Invoice Number</th>
<th>Customer</th>
<th>Final Amount ()</th>
<th>GST %</th>
<th>Total w/GST ()</th>
<th>Status</th>
<th>Invoice Date</th>
<th>Due Date</th>
<th>Action</th>
</tr>
</thead>
.invoice-management-bar {
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 17px 17px 0 0;
background: #fceeb8ff;
min-height: 54px;
padding: 15px 26px 10px 22px;
border-bottom: 1.4px solid #e8e2cf;
box-shadow: 0 1px 13px #ffe2a888;
}
<tbody>
@foreach($invoices as $i => $invoice)
<tr>
<td>{{ $i + 1 }}</td>
.invoice-management-title {
font-size: 1.32rem;
font-weight: 800;
color: #2451af;
letter-spacing: .08em;
display: flex;
align-items: center;
gap: 11px;
}
.invoice-management-title i {
font-size: 1.12em;
color: #336ad3;
}
/* Tools Row Styling */
.invoice-tools-row {
background: linear-gradient(135deg, #f8fafc 0%, #edf2f7 100%);
padding: 20px 25px;
border-bottom: 1px solid #e2e8f0;
display: flex;
justify-content: space-between;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.search-box {
display: flex;
align-items: center;
background: white;
border-radius: 10px;
padding: 8px 15px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
border: 1px solid #e2e8f0;
min-width: 300px;
flex: 1;
max-width: 400px;
}
.search-box i {
color: #64748b;
margin-right: 10px;
font-size: 1.1rem;
}
.search-box input {
border: none;
outline: none;
background: transparent;
width: 100%;
font-size: 14px;
color: #334155;
}
.search-box input::placeholder {
color: #94a3b8;
}
.filter-group {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.filter-select {
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 8px 12px;
font-size: 14px;
color: #334155;
outline: none;
min-width: 150px;
box-shadow: 0 2px 5px rgba(0,0,0,0.04);
}
.filter-select:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.create-invoice-btn {
background: linear-gradient(90deg, #226ad6, #46b4fd 123%);
padding: 10px 24px;
font-weight: 600;
border: none;
border-radius: 9px;
color: #fff;
font-size: 14px;
box-shadow: 0 2px 13px #dde7fa42;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
font-family: inherit;
text-decoration: none;
white-space: nowrap;
}
.create-invoice-btn:hover {
background: linear-gradient(90deg, #3264f8, #3acfff 140%);
box-shadow: 0 4px 25px #5ab8f880;
color: #fff;
text-decoration: none;
transform: translateY(-2px);
}
.invoice-management-main {
background: #fff;
border-radius: 0 0 17px 17px;
padding: 0;
}
/* Table Styling - CENTERED CONTENT */
.table-container {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
border-radius: 0 0 17px 17px;
}
.table-container::-webkit-scrollbar {
height: 6px;
}
.table-container::-webkit-scrollbar-thumb {
background: linear-gradient(90deg, #a7b8ff, #6c8eff);
border-radius: 10px;
}
.table-container::-webkit-scrollbar-thumb:hover {
background: linear-gradient(90deg, #5a78ff, #3f63e0);
}
.table-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.table {
width: 100%;
min-width: 1100px;
border-collapse: separate;
border-spacing: 0;
margin-bottom: 0;
}
/* Center all table content */
.table thead tr {
background: #feebbe !important;
}
.table thead th:first-child {
border-top-left-radius: 17px;
}
.table thead th:last-child {
border-top-right-radius: 17px;
}
.table thead th {
background: transparent !important;
border: none;
font-weight: 700;
color: #343535;
letter-spacing: 0.02em;
font-size: 13px;
padding: 12px 8px;
white-space: nowrap;
position: relative;
border-bottom: 2px solid #e8e2cf;
text-align: center !important; /* Center header text */
vertical-align: middle;
}
.table thead th:first-child {
padding-left: 20px;
}
.table thead th:last-child {
padding-right: 20px;
}
.table-striped tbody tr {
background: #fff;
transition: all 0.2s ease;
border-bottom: 1px solid #f1f3f4;
}
.table-striped tbody tr:hover {
background: #f8fafc !important;
}
.table-striped tbody tr:nth-of-type(odd) {
background: #f9fafc;
}
.table-striped tbody tr:nth-of-type(even) {
background: #ffffff;
}
/* Center all table cells */
.table td {
padding: 10px 8px;
border: none;
vertical-align: middle;
white-space: nowrap;
font-size: 13px;
color: #4a5568;
border-bottom: 1px solid #f1f3f4;
text-align: center !important; /* Center all cell content */
}
.table td:first-child {
padding-left: 20px;
font-weight: 600;
color: #2d3748;
}
.table td:last-child {
padding-right: 20px;
}
/* Invoice Number with Curved Boxes */
.invoice-number-cell {
display: flex;
align-items: center;
justify-content: center; /* Center the invoice number */
gap: 8px;
padding: 6px 0;
}
.invoice-icon {
width: 32px;
height: 32px;
border-radius: 8px; /* Curved border radius */
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 14px;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
font-weight: bold;
border: 2px solid rgba(255,255,255,0.3); /* Subtle border */
}
/* Different curved background colors for each invoice */
.invoice-icon-1 {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
}
.invoice-icon-2 {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
border-radius: 8px;
}
.invoice-icon-3 {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
border-radius: 8px;
}
.invoice-icon-4 {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
border-radius: 8px;
}
.invoice-icon-5 {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
border-radius: 8px;
}
.invoice-icon-6 {
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
border-radius: 8px;
}
.invoice-icon-7 {
background: linear-gradient(135deg, #d299c2 0%, #fef9d7 100%);
border-radius: 8px;
}
.invoice-icon-8 {
background: linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%);
border-radius: 8px;
}
.invoice-number-link {
color: #2469d6;
font-weight: 600;
text-decoration: none;
transition: all 0.3s ease;
font-size: 13px;
text-align: center;
}
.invoice-number-link:hover {
color: #1a4fb3;
text-decoration: none;
}
/* Badge Styling - Centered */
.badge {
font-size: 11px;
font-weight: 600;
padding: 4px 10px;
border-radius: 8px;
text-transform: uppercase;
letter-spacing: 0.3px;
display: inline-block;
text-align: center;
}
.bg-success {
background: linear-gradient(135deg, #18ce77 60%, #08ac52 110%) !important;
color: #fff !important;
}
.bg-warning {
background: linear-gradient(135deg, #ffb23c 53%, #e17800 110%) !important;
color: #fff !important;
}
.bg-danger {
background: linear-gradient(135deg, #ff5a4e 65%, #d90010 110%) !important;
color: #fff !important;
}
/* Action Button - Centered */
.btn-primary {
background: linear-gradient(135deg, #3492f8 55%, #1256cc 110%);
border: none;
border-radius: 6px;
padding: 5px 10px;
font-weight: 600;
font-size: 12px;
transition: all 0.3s ease;
box-shadow: 0 1px 4px rgba(52, 146, 248, 0.3);
color: white;
white-space: nowrap;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 4px;
}
.btn-primary:hover {
background: linear-gradient(135deg, #46b4fd 55%, #226ad6 110%);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(52, 146, 248, 0.4);
color: white;
}
/* Amount Styling - Centered */
.amount-cell {
font-weight: 600;
color: #194073;
font-size: 13px;
text-align: center !important;
}
.gst-cell {
font-weight: 500;
color: #63709b;
font-size: 13px;
text-align: center !important;
}
/* Date Styling - Centered */
.date-cell {
font-size: 12.5px;
color: #718096;
font-weight: 500;
text-align: center !important;
}
/* Customer Name Styling - Centered */
.customer-cell {
font-weight: 500;
color: #2d3748;
font-size: 13px;
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center !important;
margin: 0 auto;
}
/* Modal Styling */
.modal.fade .modal-dialog {
transition: transform 0.3s ease-out;
transform: translate(0, -50px);
}
.modal.show .modal-dialog {
transform: none;
}
.modal-content {
border: none;
border-radius: 20px;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.modal-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-bottom: none;
padding: 15px 25px;
border-radius: 20px 20px 0 0;
}
.modal-title {
font-size: 1.5rem;
font-weight: 700;
color: white;
margin: 0;
}
.modal-header .btn-close {
filter: invert(1);
opacity: 0.8;
transition: all 0.3s ease;
}
.modal-header .btn-close:hover {
opacity: 1;
transform: rotate(90deg);
}
.modal-body {
padding: 30px;
background: #f8fafc;
max-height: 70vh;
overflow-y: auto;
}
/* Responsive Design */
@media (max-width: 1200px) {
.invoice-tools-row {
flex-direction: column;
align-items: stretch;
gap: 15px;
}
.search-box {
max-width: 100%;
min-width: auto;
}
.filter-group {
justify-content: space-between;
width: 100%;
}
}
@media (max-width: 768px) {
.invoice-management-bar {
padding: 12px 20px;
}
.invoice-tools-row {
padding: 15px;
}
.table th, .table td {
font-size: 12px;
padding: 8px 6px;
}
.badge {
font-size: 10px;
padding: 3px 8px;
}
.btn-primary {
padding: 4px 8px;
font-size: 11px;
}
.filter-group {
flex-direction: column;
align-items: stretch;
}
.filter-select {
min-width: auto;
width: 100%;
}
.create-invoice-btn {
width: 100%;
justify-content: center;
}
.invoice-icon {
width: 28px;
height: 28px;
font-size: 12px;
}
}
/* Empty State - Centered */
.text-muted {
color: #8a9bb9 !important;
font-style: italic;
padding: 30px !important;
text-align: center;
font-size: 14px;
}
/* Card Styling */
.card {
border-radius: 0 0 17px 17px;
border: none;
margin-bottom: 0 !important;
box-shadow: none;
}
.card-header {
background: #f8f9fa !important;
border-bottom: 1px solid #e9ecef;
border-radius: 0 !important;
padding: 15px 25px;
text-align: center;
}
.card-header h4 {
margin: 0;
color: #2451af;
font-weight: 700;
font-size: 1.3rem;
text-align: center;
}
/* Stats Summary - Centered */
.stats-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
margin: 20px 25px;
padding: 0;
}
.stat-card {
background: white;
padding: 15px;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
text-align: center;
border-left: 3px solid #667eea;
}
.stat-value {
font-size: 1.5rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 3px;
text-align: center;
}
.stat-label {
font-size: 0.85rem;
color: #718096;
font-weight: 600;
text-align: center;
}
/* Column Headers - Centered */
.column-header {
text-align: center !important;
font-weight: 600;
color: #2d3748;
}
/* Remove extra spacing */
.no-extra-space {
margin: 0;
padding: 0;
}
.compact-view {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
/* Ensure all content in table is centered */
.table tbody tr td {
text-align: center !important;
}
.table tbody tr td .invoice-number-cell {
justify-content: center;
}
.table tbody tr td .btn-primary {
margin: 0 auto;
}
</style>
<div class="container-fluid py-3">
<!-- INVOICE MANAGEMENT -->
<div class="invoice-management-box">
<div class="invoice-management-bar">
<span class="invoice-management-title">
<i class="bi bi-receipt"></i> Invoice Management
</span>
</div>
<!-- TOOLS ROW - Search, Filter, Create Button -->
<div class="invoice-tools-row">
<!-- Search Box -->
<div class="search-box">
<i class="bi bi-search"></i>
<input type="text" id="invoiceSearch" placeholder="Search by invoice number, customer name...">
</div>
<!-- Filter Group -->
<div class="filter-group">
<select class="filter-select" id="statusFilter">
<option value="">All Status</option>
<option value="paid">Paid</option>
<option value="pending">Pending</option>
<option value="overdue">Overdue</option>
</select>
<select class="filter-select" id="dateFilter">
<option value="">All Dates</option>
<option value="today">Today</option>
<option value="week">This Week</option>
<option value="month">This Month</option>
</select>
<select class="filter-select" id="amountFilter">
<option value="">Any Amount</option>
<option value="0-1000">₹0 - ₹1,000</option>
<option value="1000-5000">₹1,000 - ₹5,000</option>
<option value="5000+">₹5,000+</option>
</select>
</div>
<!-- Create Invoice Button -->
<a href="{{ route('admin.invoices.create') }}" class="create-invoice-btn">
<i class="bi bi-plus-circle"></i> Create Invoice
</a>
</div>
<div class="invoice-management-main no-extra-space">
<!-- Quick Stats Summary -->
<div class="stats-summary">
<div class="stat-card">
<div class="stat-value">{{ $invoices->count() }}</div>
<div class="stat-label">Total Invoices</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ number_format($invoices->sum('final_amount_with_gst'), 2) }}</div>
<div class="stat-label">Total Revenue</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ $invoices->where('status', 'paid')->count() }}</div>
<div class="stat-label">Paid Invoices</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ $invoices->where('status', 'pending')->count() }}</div>
<div class="stat-label">Pending Invoices</div>
</div>
</div>
<!-- ALL INVOICES TABLE -->
<div class="card shadow-sm">
<div class="card-header bg-light d-flex justify-content-between align-items-center compact-view">
<h4 class="mb-0">All Invoices</h4>
<span class="text-muted" style="font-size: 12px;">
{{ $invoices->count() }} invoices
</span>
</div>
<div class="card-body p-0">
<div class="table-container">
<table class="table table-striped align-middle" id="invoicesTable">
<thead class="table-light">
<tr>
<th class="column-header">#</th>
<th class="column-header">Invoice Number</th>
<th class="column-header">Customer</th>
<th class="column-header">Final Amount</th>
<th class="column-header">GST %</th>
<th class="column-header">Total w/GST</th>
<th class="column-header">Status</th>
<th class="column-header">Invoice Date</th>
<th class="column-header">Due Date</th>
<th class="column-header">Action</th>
</tr>
</thead>
<tbody>
@php
$totalInvoices = $invoices->count();
$sortedInvoices = $invoices->sortByDesc('created_at'); // Latest first
@endphp
@forelse($sortedInvoices as $i => $invoice)
<tr>
<td>{{ $totalInvoices - $i }}</td>
<td>
<a href="#"
class="text-primary fw-bold open-invoice-popup"
data-id="{{ $invoice->id }}">
{{ $invoice->invoice_number }}
<div class="invoice-number-cell">
<div class="invoice-icon invoice-icon-{{ (($totalInvoices - $i) % 8) + 1 }}">
<i class="bi bi-file-earmark-text"></i>
</div>
<a href="#" class="invoice-number-link open-invoice-popup" data-id="{{ $invoice->id }}">
{{ $invoice->invoice_number }}
</a>
</div>
</td>
<td>{{ $invoice->customer_name }}</td>
<td class="customer-cell">{{ $invoice->customer_name }}</td>
<td>{{ number_format($invoice->final_amount, 2) }}</td>
<td>{{ $invoice->gst_percent }}%</td>
<td>{{ number_format($invoice->final_amount_with_gst, 2) }}</td>
<td class="amount-cell">{{ number_format($invoice->final_amount, 2) }}</td>
<td class="gst-cell">{{ $invoice->gst_percent }}%</td>
<td class="amount-cell">{{ number_format($invoice->final_amount_with_gst, 2) }}</td>
<td>
<span class="badge
@if($invoice->status=='paid') bg-success
@elseif($invoice->status=='overdue') bg-danger
@else bg-warning text-dark @endif">
{{ ucfirst($invoice->status) }}
</span>
<span class="badge
@if($invoice->status=='paid') bg-success
@elseif($invoice->status=='overdue') bg-danger
@else bg-warning @endif">
{{ ucfirst($invoice->status) }}
</span>
</td>
<td>{{ $invoice->invoice_date }}</td>
<td>{{ $invoice->due_date }}</td>
<td class="date-cell">{{ $invoice->invoice_date }}</td>
<td class="date-cell">{{ $invoice->due_date }}</td>
<td>
<a href="{{ route('admin.invoices.edit', $invoice->id) }}"
class="btn btn-sm btn-primary">
Edit
</a>
<a href="{{ route('admin.invoices.edit', $invoice->id) }}"
class="btn btn-sm btn-primary">
<i class="bi bi-pencil"></i> Edit
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</tr>
@empty
<tr>
<td colspan="10" class="text-muted">No invoices found</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{{-- POPUP MODAL --}}
<div class="modal fade" id="invoiceModal" tabindex="-1">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Invoice Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="invoiceModalBody">
<p class="text-center text-muted">Loading...</p>
</div>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Invoice Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="invoiceModalBody">
<p class="text-center text-muted">Loading...</p>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('click', function(e) {
document.addEventListener('DOMContentLoaded', function() {
// Invoice popup functionality
document.addEventListener('click', function(e) {
if (e.target.closest('.open-invoice-popup')) {
e.preventDefault();
const id = e.target.closest('.open-invoice-popup').dataset.id;
const modal = new bootstrap.Modal(document.getElementById('invoiceModal'));
e.preventDefault();
const id = e.target.closest('.open-invoice-popup').dataset.id;
const modal = new bootstrap.Modal(document.getElementById('invoiceModal'));
document.getElementById('invoiceModalBody').innerHTML =
"<p class='text-center text-muted'>Loading...</p>";
document.getElementById('invoiceModalBody').innerHTML =
"<div class='text-center py-4'><div class='spinner-border text-primary' role='status'></div><p class='mt-2 text-muted'>Loading invoice details...</p></div>";
modal.show();
modal.show();
fetch(`/admin/invoices/${id}/popup`)
.then(res => res.text())
.then(html => {
document.getElementById('invoiceModalBody').innerHTML = html;
});
fetch(`/admin/invoices/${id}/popup`)
.then(res => {
if (!res.ok) {
throw new Error('Network response was not ok');
}
return res.text();
})
.then(html => {
document.getElementById('invoiceModalBody').innerHTML = html;
})
.catch(error => {
console.error('Error loading invoice details:', error);
document.getElementById('invoiceModalBody').innerHTML =
"<div class='text-center py-4 text-danger'><i class='bi bi-exclamation-triangle fs-1'></i><p class='mt-2'>Failed to load invoice details. Please try again.</p></div>";
});
}
});
// Search functionality
const searchInput = document.getElementById('invoiceSearch');
const statusFilter = document.getElementById('statusFilter');
const dateFilter = document.getElementById('dateFilter');
const amountFilter = document.getElementById('amountFilter');
const table = document.getElementById('invoicesTable');
const tableRows = table.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
function filterInvoices() {
const searchTerm = searchInput.value.toLowerCase();
const statusValue = statusFilter.value;
const dateValue = dateFilter.value;
const amountValue = amountFilter.value;
for (let row of tableRows) {
const cells = row.getElementsByTagName('td');
if (cells.length < 9) continue;
const invoiceNumber = cells[1].textContent.toLowerCase();
const customerName = cells[2].textContent.toLowerCase();
const status = cells[6].textContent.toLowerCase();
const amount = parseFloat(cells[3].textContent.replace('₹', '').replace(',', ''));
const matchesSearch = invoiceNumber.includes(searchTerm) || customerName.includes(searchTerm);
const matchesStatus = !statusValue || status.includes(statusValue);
const matchesAmount = !amountValue || (
amountValue === '0-1000' ? amount <= 1000 :
amountValue === '1000-5000' ? amount > 1000 && amount <= 5000 :
amountValue === '5000+' ? amount > 5000 : true
);
row.style.display = matchesSearch && matchesStatus && matchesAmount ? '' : 'none';
}
}
// Add event listeners for filtering
searchInput.addEventListener('input', filterInvoices);
statusFilter.addEventListener('change', filterInvoices);
dateFilter.addEventListener('change', filterInvoices);
amountFilter.addEventListener('change', filterInvoices);
// Add hover effects to table rows
for (let row of tableRows) {
row.addEventListener('mouseenter', function() {
this.style.cursor = 'pointer';
});
}
});
</script>

View File

@@ -3,6 +3,357 @@
@section('page-title', 'Edit Invoice')
@section('content')
<style>
/* World-Class UI Design System - No Blur Effects */
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--success-gradient: linear-gradient(135deg, #10b981 0%, #059669 100%);
--glass-bg: #ffffff;
--glass-border: rgba(255, 255, 255, 0.2);
--shadow-soft: 0 8px 32px rgba(0, 0, 0, 0.1);
--shadow-medium: 0 12px 48px rgba(0, 0, 0, 0.15);
--shadow-strong: 0 20px 60px rgba(0, 0, 0, 0.2);
}
/* Enhanced Card - No Blur */
.card {
background: var(--glass-bg);
border-radius: 24px;
box-shadow: var(--shadow-strong);
border: 1px solid #e4e6ef;
animation: cardEntrance 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
position: relative;
overflow: hidden;
}
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg,
rgba(102, 126, 234, 0.03) 0%,
rgba(118, 75, 162, 0.03) 50%,
rgba(16, 185, 129, 0.03) 100%);
pointer-events: none;
}
@keyframes cardEntrance {
0% {
opacity: 0;
transform: translateY(30px) scale(0.95);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* Premium Card Header */
.card-header {
background: var(--primary-gradient);
color: white;
border-bottom: none;
padding: 28px 35px;
position: relative;
overflow: hidden;
}
.card-header::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(45deg,
transparent 0%,
rgba(255, 255, 255, 0.1) 50%,
transparent 100%);
animation: headerShimmer 6s infinite linear;
transform: rotate(45deg);
}
@keyframes headerShimmer {
0% { transform: translateX(-100%) rotate(45deg); }
100% { transform: translateX(100%) rotate(45deg); }
}
.card-header h4 {
margin: 0;
font-weight: 800;
font-size: 1.6rem;
position: relative;
display: flex;
align-items: center;
gap: 12px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.card-header h4::before {
content: '✨';
font-size: 1.4rem;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
.card-body {
padding: 35px;
background: #f8fafc;
position: relative;
}
/* World-Class Form Elements - No Blur */
.form-label {
font-weight: 700;
color: #1e293b;
margin-bottom: 10px;
font-size: 0.95rem;
display: flex;
align-items: center;
gap: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
position: relative;
}
.form-label::before {
content: '';
width: 4px;
height: 16px;
background: var(--primary-gradient);
border-radius: 2px;
display: inline-block;
}
.form-control, .form-select {
border: 2px solid #e2e8f0;
border-radius: 16px;
padding: 16px 20px;
font-size: 1rem;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
background: #ffffff;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
position: relative;
}
.form-control:focus, .form-select:focus {
border-color: #667eea;
box-shadow:
0 0 0 4px rgba(102, 126, 234, 0.15),
0 8px 24px rgba(102, 126, 234, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.8);
background: #ffffff;
transform: translateY(-2px) scale(1.02);
animation: inputGlow 2s infinite;
}
@keyframes inputGlow {
0%, 100% { box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.15), 0 8px 24px rgba(102, 126, 234, 0.2); }
50% { box-shadow: 0 0 0 6px rgba(102, 126, 234, 0.1), 0 12px 32px rgba(102, 126, 234, 0.25); }
}
.form-control:hover, .form-select:hover {
border-color: #cbd5e1;
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
}
/* Enhanced Grid System */
.row.g-3 {
margin: -15px;
}
.row.g-3 > [class*="col-"] {
padding: 15px;
animation: formElementEntrance 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
@keyframes formElementEntrance {
0% {
opacity: 0;
transform: translateY(25px) scale(0.9);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* Staggered Animation Delays */
.row.g-3 > [class*="col-"]:nth-child(1) { animation-delay: 0.1s; }
.row.g-3 > [class*="col-"]:nth-child(2) { animation-delay: 0.2s; }
.row.g-3 > [class*="col-"]:nth-child(3) { animation-delay: 0.3s; }
.row.g-3 > [class*="col-"]:nth-child(4) { animation-delay: 0.4s; }
.row.g-3 > [class*="col-"]:nth-child(5) { animation-delay: 0.5s; }
.row.g-3 > [class*="col-"]:nth-child(6) { animation-delay: 0.6s; }
.row.g-3 > [class*="col-"]:nth-child(7) { animation-delay: 0.7s; }
.row.g-3 > [class*="col-"]:nth-child(8) { animation-delay: 0.8s; }
/* Premium Textarea */
textarea.form-control {
resize: vertical;
min-height: 120px;
line-height: 1.6;
background: #ffffff;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
textarea.form-control:focus {
transform: translateY(-2px) scale(1.01);
box-shadow:
0 0 0 4px rgba(102, 126, 234, 0.15),
0 12px 32px rgba(102, 126, 234, 0.2);
}
/* World-Class Button Design - No Blur */
.btn-success {
background: var(--success-gradient);
border: none;
padding: 18px 45px;
border-radius: 16px;
color: white;
font-weight: 700;
font-size: 1.1rem;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: var(--shadow-medium);
position: relative;
overflow: hidden;
}
.btn-success::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent,
rgba(255, 255, 255, 0.4),
transparent);
transition: left 0.6s ease;
}
.btn-success:hover::before {
left: 100%;
}
.btn-success:hover {
transform: translateY(-4px) scale(1.05);
box-shadow:
0 16px 40px rgba(16, 185, 129, 0.4),
0 0 0 1px rgba(255, 255, 255, 0.1);
background: var(--success-gradient);
}
.btn-success:active {
transform: translateY(-1px) scale(1.02);
transition: all 0.1s ease;
}
/* Enhanced Select Styling */
.form-select {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23667eea' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
background-position: right 20px center;
background-repeat: no-repeat;
background-size: 18px;
padding-right: 50px;
cursor: pointer;
appearance: none;
}
/* Advanced Loading Animation */
.btn-success.loading {
pointer-events: none;
padding-right: 60px;
}
.btn-success.loading::after {
content: '';
position: absolute;
right: 20px;
top: 50%;
width: 20px;
height: 20px;
margin-top: -10px;
border: 2px solid transparent;
border-top: 2px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Premium Focus States */
.form-control:focus-visible,
.form-select:focus-visible,
.btn-success:focus-visible {
outline: 3px solid #667eea;
outline-offset: 2px;
border-radius: 8px;
}
/* Advanced Responsive Design */
@media (max-width: 768px) {
.card-body {
padding: 25px 20px;
}
.card-header {
padding: 22px 25px;
}
.card-header h4 {
font-size: 1.4rem;
}
.btn-success {
width: 100%;
padding: 16px 30px;
font-size: 1rem;
}
.form-control, .form-select {
padding: 14px 16px;
}
}
/* Micro-interactions for Enhanced UX */
.form-control:valid {
border-left: 3px solid #10b981;
}
.form-control:invalid:not(:focus):not(:placeholder-shown) {
border-left: 3px solid #ef4444;
animation: shake 0.5s ease-in-out;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
/* Smooth scrolling for better UX */
html {
scroll-behavior: smooth;
}
/* Performance optimized animations */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
</style>
<div class="card shadow-sm">
<div class="card-header bg-light">
@@ -10,7 +361,6 @@
</div>
<div class="card-body">
<form action="{{ route('admin.invoices.update', $invoice->id) }}" method="POST">
@csrf
@@ -82,8 +432,50 @@
</div>
</form>
</div>
</div>
<script>
// World-Class Interactive Enhancements - No Parallax
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('form');
const submitBtn = document.querySelector('.btn-success');
const inputs = document.querySelectorAll('input, select, textarea');
// Enhanced form submission
form.addEventListener('submit', function(e) {
submitBtn.classList.add('loading');
submitBtn.innerHTML = 'Updating Invoice...';
// Add a small delay to show loading state
setTimeout(() => {
if (!form.checkValidity()) {
submitBtn.classList.remove('loading');
submitBtn.innerHTML = 'Update Invoice';
}
}, 100);
});
// Real-time validation with visual feedback
inputs.forEach(input => {
input.addEventListener('input', function() {
if (this.checkValidity()) {
this.style.borderLeftColor = '#10b981';
} else {
this.style.borderLeftColor = '#ef4444';
}
});
// Add focus effects
input.addEventListener('focus', function() {
this.parentElement.style.transform = 'translateY(-2px)';
});
input.addEventListener('blur', function() {
this.parentElement.style.transform = 'translateY(0)';
});
});
});
</script>
@endsection

View File

@@ -5,6 +5,8 @@
<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">
<style>
body {
margin: 0;

View File

@@ -3,98 +3,135 @@
<head>
<meta charset="UTF-8">
<title>{{ $invoice->invoice_number }}</title>
<style>
body {
font-family: sans-serif;
font-size: 13px;
color: #333;
font-family: 'Segoe UI', 'Roboto', Arial, sans-serif;
font-size: 14px;
background: #f6f8fb;
color: #2f3440;
letter-spacing: 0.02em;
}
.header-box {
text-align: center;
padding: 10px 0;
border-bottom: 2px solid #000;
margin-bottom: 20px;
border-bottom: 3px solid #1b2430;
background: linear-gradient(to right, #0766ad 0%, #85c6ee 100%);
padding: 26px 0 18px 0;
margin-bottom: 28px;
border-radius: 0 0 15px 15px;
box-shadow: 0 2px 12px rgba(35,82,124,0.08);
}
.logo {
width: 120px;
margin-bottom: 8px;
margin-bottom: 12px;
filter: drop-shadow(0 2px 5px #0001);
}
.title {
font-size: 22px;
font-size: 28px;
font-weight: bold;
color: #000;
color: #1a4c8b;
letter-spacing: 2px;
margin-bottom: 5px;
text-shadow: 0 2px 9px #90caf944;
}
.subtitle {
font-size: 14px;
font-size: 15px;
margin-top: 3px;
color: #666;
color: #376f9e;
font-weight: 500;
letter-spacing: 1px;
}
.section-title {
font-size: 16px;
font-size: 19px;
font-weight: bold;
margin-top: 20px;
margin-bottom: 6px;
color: #222;
margin-top: 28px;
margin-bottom: 10px;
color: #0766ad;
text-transform: uppercase;
letter-spacing: 1px;
border-left: 4px solid #0766ad;
padding-left: 12px;
}
.info-box {
border: 1px solid #ccc;
padding: 10px;
line-height: 1.6;
background: #f9f9f9;
border: 1px solid #d3e3fd;
padding: 13px 18px;
line-height: 1.8;
background: #ecf7ff;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(100,143,176,0.05);
margin-bottom: 7px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 12px;
margin-top: 15px;
background: #fff;
box-shadow: 0 2px 18px rgba(91,146,196,0.05);
border-radius: 10px;
overflow: hidden;
}
th {
background: #efefef;
padding: 6px;
font-size: 13px;
font-weight: bold;
border: 1px solid #444;
}
td {
padding: 6px;
border: 1px solid #444;
font-size: 12px;
}
.totals-box {
margin-top: 20px;
padding: 10px;
border: 1px solid #bbb;
background: #fafafa;
background: linear-gradient(90deg, #e3f1fb 80%, #f0f6ff 100%);
padding: 10px 7px;
font-size: 14px;
line-height: 1.8;
font-weight: 700;
color: #085d99;
border: 1px solid #b1cbe1;
text-align: center;
}
td {
padding: 8px 7px;
border: 1px solid #dae5ec;
color: #395471;
font-size: 13px;
background: #fafcff;
text-align: center;
}
tbody tr:nth-child(even) td {
background: #f3fafd;
}
tbody tr:hover td {
background: #e2f1fa;
transition: background 0.2s;
}
.totals-box {
margin-top: 22px;
margin-bottom: 16px;
padding: 14px 22px;
border: 1.5px solid #b1cbe1;
background: linear-gradient(90deg, #eaf6fb 70%, #f8fbfe 100%);
font-size: 16px;
line-height: 2.1;
border-radius: 11px;
box-shadow: 0 2px 10px rgba(120,160,200,0.08);
}
.totals-box strong {
color: #0766ad;
font-size: 15.5px;
}
@media (max-width: 680px) {
.header-box, .info-box, .totals-box {
padding: 10px;
}
.section-title {
font-size: 15.5px;
padding-left: 7px;
margin-bottom: 7px;
margin-top: 20px;
}
th, td {
font-size: 12px;
padding: 5px;
}
}
</style>
</head>
<body>
<!-- HEADER -->
<div class="header-box">
<!-- LOGO -->
<img src="{{ public_path('images/kent_logo2.png') }}" class="logo">
<img src="{{ public_path('images/kent_logo2.png') }}" alt="logo" class="logo">
<div class="title">KENT LOGISTICS</div>
<div class="subtitle">Official Invoice</div>
</div>
<!-- INVOICE INFO -->
<div class="info-box">
<strong>Invoice No:</strong> {{ $invoice->invoice_number }} <br>
@@ -102,7 +139,6 @@
<strong>Due Date:</strong> {{ $invoice->due_date }} <br>
<strong>Status:</strong> {{ ucfirst($invoice->status) }}
</div>
<!-- CUSTOMER DETAILS -->
<div class="section-title">Customer Details</div>
<div class="info-box">
@@ -112,10 +148,8 @@
{{ $invoice->customer_email }} <br>
{{ $invoice->customer_address }}
</div>
<!-- ITEMS TABLE -->
<div class="section-title">Invoice Items</div>
<table>
<thead>
<tr>
@@ -134,7 +168,6 @@
<th>Shop No</th>
</tr>
</thead>
<tbody>
@foreach($invoice->items as $i => $item)
<tr>
@@ -155,15 +188,12 @@
@endforeach
</tbody>
</table>
<!-- TOTALS -->
<div class="section-title">Totals</div>
<div class="totals-box">
<strong>Amount:</strong> {{ number_format($invoice->final_amount, 2) }} <br>
<strong>GST ({{ $invoice->gst_percent }}%):</strong> {{ number_format($invoice->gst_amount, 2) }} <br>
<strong>Total With GST:</strong> <strong>{{ number_format($invoice->final_amount_with_gst, 2) }}</strong>
</div>
</body>
</html>

View File

@@ -1,73 +1,207 @@
<div>
<h4 class="fw-bold mb-2">
Invoice: {{ $invoice->invoice_number }}
</h4>
<p><strong>Invoice Date:</strong> {{ $invoice->invoice_date }}</p>
<p><strong>Due Date:</strong> {{ $invoice->due_date }}</p>
<hr>
<h5>Customer Details</h5>
<p>
<strong>{{ $invoice->customer_name }}</strong><br>
{{ $invoice->company_name }}<br>
{{ $invoice->customer_mobile }}<br>
{{ $invoice->customer_email }}<br>
{{ $invoice->customer_address }}
</p>
<hr>
<h5>Invoice Items</h5>
<div class="table-responsive">
<table class="table table-bordered align-middle text-center">
<thead class="table-light">
<tr>
<th>#</th>
<th>Description</th>
<th>CTN</th>
<th>QTY</th>
<th>TTL/QTY</th>
<th>Unit</th>
<th>Price</th>
<th>TTL Amount</th>
<th>CBM</th>
<th>TTL CBM</th>
<th>KG</th>
<th>TTL KG</th>
<th>Shop No</th>
</tr>
</thead>
<tbody>
@foreach($invoice->items as $i => $item)
<tr>
<td>{{ $i+1 }}</td>
<td>{{ $item->description }}</td>
<td>{{ $item->ctn }}</td>
<td>{{ $item->qty }}</td>
<td>{{ $item->ttl_qty }}</td>
<td>{{ $item->unit }}</td>
<td>{{ number_format($item->price,2) }}</td>
<td>{{ number_format($item->ttl_amount,2) }}</td>
<td>{{ $item->cbm }}</td>
<td>{{ $item->ttl_cbm }}</td>
<td>{{ $item->kg }}</td>
<td>{{ $item->ttl_kg }}</td>
<td>{{ $item->shop_no }}</td>
</tr>
@endforeach
</tbody>
</table>
<div class="p-4">
<!-- Invoice Header -->
<div class="row mb-4">
<div class="col-md-6">
<h2 class="fw-bold text-primary 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">
<div class="d-inline-block bg-light rounded-3 p-3">
<span class="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
fs-6 px-3 py-2">
<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>
<hr>
<!-- Dates - Compact Professional Layout -->
<div class="row mb-3">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-body py-2">
<div class="row align-items-center text-center">
<div class="col-md-5">
<div class="mb-0">
<div class="text-muted fw-semibold small">INVOICE DATE</div>
</div>
<div class="fw-bold text-dark" style="font-size: 0.95rem;">
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}
</div>
</div>
<div class="col-md-2">
<div class="date-connector">
<i class="fas fa-arrow-right text-muted small"></i>
</div>
</div>
<div class="col-md-5">
<div class="mb-0">
<div class="text-muted fw-semibold small">DUE DATE</div>
</div>
<div class="fw-bold @if($invoice->status == 'overdue') text-danger @else text-dark @endif" style="font-size: 0.95rem;">
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<h5>Final Summary</h5>
<p><strong>Amount:</strong> {{ number_format($invoice->final_amount,2) }}</p>
<p><strong>GST ({{ $invoice->gst_percent }}%):</strong> {{ number_format($invoice->gst_amount,2) }}</p>
<p><strong>Total With GST:</strong> {{ number_format($invoice->final_amount_with_gst,2) }}</p>
<!-- Customer Details -->
<div class="row mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-header bg-light py-2">
<h6 class="mb-0 fw-bold text-dark">
<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)
<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-0">
<strong>Address:</strong><br>
{{ $invoice->customer_address }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<p><strong>Status:</strong> {{ ucfirst($invoice->status) }}</p>
<!-- Invoice Items -->
<div class="row mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-header bg-light py-2">
<h6 class="mb-0 fw-bold text-dark">
<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>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Final Summary -->
<div class="row">
<div class="col-md-6 offset-md-6">
<div class="card border-0 bg-light">
<div class="card-header bg-dark text-white py-2">
<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="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>
<div class="d-flex justify-content-between align-items-center pt-1">
<span class="fw-bold text-dark">Total With GST:</span>
<span class="fw-bold text-success">{{ number_format($invoice->final_amount_with_gst,2) }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.date-connector {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: #6c757d;
}
.date-connector i {
background: #f8f9fa;
padding: 4px;
border-radius: 50%;
border: 1px solid #e9ecef;
}
.card {
border-radius: 6px;
}
.table {
margin-bottom: 0;
}
.table > :not(caption) > * > * {
padding: 10px 6px;
}
</style>

View File

@@ -113,6 +113,10 @@ Route::prefix('admin')->middleware('auth:admin')->group(function () {
Route::post('/invoices/{id}/update', [AdminInvoiceController::class, 'update'])
->name('admin.invoices.update');
//Add New Invoice
Route::get('/admin/invoices/create', [InvoiceController::class, 'create'])->name('admin.invoices.create');
});