diff --git a/.env.example b/.env.example index ec7f031..d595fff 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,11 @@ -APP_NAME=Laravel +APP_NAME="KOL-Manager" APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://localhost # ── App Gate Password ───────────────────────────────────────────────────────── -APP_PASSWORD= +APP_PASSWORD=admin123 APP_LOCALE=en APP_FALLBACK_LOCALE=en diff --git a/Dockerfile b/Dockerfile index 6dffabb..9e10dbe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -92,12 +92,14 @@ RUN mkdir -p \ storage/framework/cache \ storage/framework/sessions \ storage/framework/views \ + storage \ bootstrap/cache \ database \ && chown -R www-data:www-data \ storage \ bootstrap/cache \ database \ + /var/lib/nginx \ && chmod -R 775 \ storage \ bootstrap/cache \ diff --git a/docker-compose.yml b/docker-compose.yml index 865a926..e81be8c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,8 @@ services: container_name: kol-manager restart: unless-stopped - ports: - - "${APP_PORT:-8080}:80" + # ports: + # - "${APP_PORT:-8080}:80" # Mount .env.docker as the runtime .env env_file: @@ -22,7 +22,7 @@ services: - kol_storage:/var/www/html/storage healthcheck: - test: ["CMD", "curl", "-f", "http://localhost/up"] + test: [ "CMD", "curl", "-f", "http://localhost/up" ] interval: 30s timeout: 10s retries: 3 diff --git a/resources/views/clients/show.blade.php b/resources/views/clients/show.blade.php index 59df90f..d3ad498 100644 --- a/resources/views/clients/show.blade.php +++ b/resources/views/clients/show.blade.php @@ -18,9 +18,22 @@ const fd = new FormData(); fd.append('avatar', input.files[0]); fd.append('_token', document.querySelector('meta[name=csrf-token]').content); - const res = await fetch('{{ route('clients.upload-avatar', $client) }}', { method: 'POST', body: fd }); - const data = await res.json(); - if (res.ok) this.avatarUrl = data.url + '?t=' + Date.now(); + try { + const res = await fetch('{{ route('clients.upload-avatar', $client->id, false) }}', { + method: 'POST', + body: fd, + headers: { 'Accept': 'application/json' } + }); + const data = await res.json(); + if (res.ok) { + this.avatarUrl = data.url + '?t=' + Date.now(); + } else { + alert(data.message || 'Upload failed'); + } + } catch (err) { + console.error('Avatar upload error:', err); + alert('Network Error. Could not upload.'); + } this.uploading = false; input.value = ''; }, @@ -29,8 +42,16 @@ const fd = new FormData(); fd.append('_token', document.querySelector('meta[name=csrf-token]').content); fd.append('_method', 'DELETE'); - await fetch('{{ route('clients.delete-avatar', $client) }}', { method: 'POST', body: fd }); - this.avatarUrl = ''; + try { + await fetch('{{ route('clients.delete-avatar', $client->id, false) }}', { + method: 'POST', + body: fd, + headers: { 'Accept': 'application/json' } + }); + this.avatarUrl = ''; + } catch (err) { + console.error(err); + } } }">
diff --git a/resources/views/invoices/pdf.blade.php b/resources/views/invoices/pdf.blade.php index 0b2bce7..0698668 100644 --- a/resources/views/invoices/pdf.blade.php +++ b/resources/views/invoices/pdf.blade.php @@ -303,8 +303,8 @@ Description - Qty Unit Price + Qty Total @@ -318,8 +318,8 @@ style="margin-left:6px; font-size:10px; background:#F3F4F6; color:#6B7280; padding:2px 8px; border-radius:10px; font-weight:600;">Non-Taxable @endif - {{ $item->quantity }} Rp {{ number_format($item->unit_price, 0, ',', '.') }} + {{ $item->quantity }} Rp {{ number_format($item->total, 0, ',', '.') }} @endforeach @@ -361,17 +361,18 @@
@endif -
- @if($invoice->notes) -
{{ $invoice->notes }}
- @endif + @if($invoice->notes) +
{{ $invoice->notes }}
+ @endif +
@if($invoice->signature_image && file_exists(storage_path('app/public/' . $invoice->signature_image)))
Jakarta, {{ $invoice->issue_date->format('d F Y') }}
- +
{{ $invoice->signer_name ?: ($invoiceSettings->signer_name ?: ($invoiceSettings->header_name ?: 'Signature')) }}
@@ -386,7 +387,7 @@
- + diff --git a/resources/views/invoices/settings.blade.php b/resources/views/invoices/settings.blade.php index 41651c7..5c184f5 100644 --- a/resources/views/invoices/settings.blade.php +++ b/resources/views/invoices/settings.blade.php @@ -72,14 +72,21 @@ fd.append('header_logo', input.files[0]); fd.append('_token', document.querySelector('meta[name=csrf-token]').content); try { - const res = await fetch('{{ route('invoice-settings.upload-logo', [], false) }}', { method: 'POST', body: fd }); + const res = await fetch('{{ route('invoice-settings.upload-logo', [], false) }}', { + method: 'POST', + body: fd, + headers: { + 'Accept': 'application/json' + } + }); const data = await res.json(); if (res.ok) { this.logoUrl = data.url + '?t=' + Date.now(); } else { this.errorMsg = data.message ?? 'Upload failed.'; } - } catch { + } catch (err) { + console.error(err); this.errorMsg = 'Network error. Please try again.'; } this.uploading = false; @@ -91,7 +98,11 @@ const fd = new FormData(); fd.append('_token', document.querySelector('meta[name=csrf-token]').content); fd.append('_method', 'DELETE'); - await fetch('{{ route('invoice-settings.delete-logo', [], false) }}', { method: 'POST', body: fd }); + await fetch('{{ route('invoice-settings.delete-logo', [], false) }}', { + method: 'POST', + body: fd, + headers: { 'Accept': 'application/json' } + }); this.logoUrl = ''; } }"> @@ -234,14 +245,21 @@ fd.append('signature_image', input.files[0]); fd.append('_token', document.querySelector('meta[name=csrf-token]').content); try { - const res = await fetch('{{ route('invoice-settings.upload-signature', [], false) }}', { method: 'POST', body: fd }); + const res = await fetch('{{ route('invoice-settings.upload-signature', [], false) }}', { + method: 'POST', + body: fd, + headers: { + 'Accept': 'application/json' + } + }); const data = await res.json(); if (res.ok) { this.signatureUrl = data.url + '?t=' + Date.now(); } else { this.errorMsg = data.message ?? 'Upload failed.'; } - } catch { + } catch (err) { + console.error(err); this.errorMsg = 'Network error. Please try again.'; } this.uploading = false; @@ -253,7 +271,11 @@ const fd = new FormData(); fd.append('_token', document.querySelector('meta[name=csrf-token]').content); fd.append('_method', 'DELETE'); - await fetch('{{ route('invoice-settings.delete-signature', [], false) }}', { method: 'POST', body: fd }); + await fetch('{{ route('invoice-settings.delete-signature', [], false) }}', { + method: 'POST', + body: fd, + headers: { 'Accept': 'application/json' } + }); this.signatureUrl = ''; } }"> diff --git a/resources/views/invoices/show.blade.php b/resources/views/invoices/show.blade.php index 6027b3f..b521aae 100644 --- a/resources/views/invoices/show.blade.php +++ b/resources/views/invoices/show.blade.php @@ -90,8 +90,8 @@ Description - Qty Unit Price + Qty Total @@ -105,9 +105,9 @@ class="ml-1.5 text-xs bg-gray-100 text-gray-500 px-2 py-0.5 rounded-full font-medium">Non-Taxable @endif - {{ $item->quantity }} Rp {{ number_format($item->unit_price, 0, ',', '.') }} + {{ $item->quantity }} Rp {{ number_format($item->total, 0, ',', '.') }} @@ -137,7 +137,7 @@ {{-- Bank Info --}} @if($invoice->bank_name) -
+
💳 Payment Info
{{ $invoice->bank_name }} @@ -147,12 +147,11 @@
@endif -
-
- @if($invoice->notes) -
{{ $invoice->notes }}
- @endif -
+ @if($invoice->notes) +
{{ $invoice->notes }}
+ @endif + +
@if($invoice->signature_image)