1115 lines
65 KiB
PHP

@extends('layouts.app')
@section('title', 'Suppliers')
@section('content')
{{-- ── Page Header ─────────────────────────────────────────────────────────── --}}
<div class="page-header">
<div>
<h1 class="page-title">Suppliers</h1>
<p class="page-subtitle">Manage your supplier directory</p>
</div>
<div class="flex items-center gap-2 flex-wrap">
<a href="{{ route('purchase.suppliers.export-pdf') }}" class="btn btn-secondary" title="Export as PDF">
<svg width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6M9 17h4"/>
</svg>
Export PDF
</a>
<a href="{{ route('purchase.suppliers.template') }}" class="btn btn-secondary" title="Download import template">
<svg width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
</svg>
Template
</a>
<button onclick="document.getElementById('import-modal').classList.remove('hidden')" class="btn btn-success">
<svg width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
</svg>
Import Excel
</button>
<button onclick="openNewSupplierModal()" class="btn-primary" style="display:inline-flex;align-items:center;gap:6px;">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 4v16m8-8H4"/>
</svg>
Add Supplier
</button>
</div>
</div>
{{-- ── Stat Cards ───────────────────────────────────────────────────────────── --}}
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:20px;">
<div style="background:#fff;border-radius:12px;padding:18px 20px;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,.04);display:flex;align-items:center;gap:14px;">
<div style="width:44px;height:44px;border-radius:10px;background:#eff6ff;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="20" height="20" fill="none" stroke="#2563eb" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M17 20h5v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2h5M12 12a4 4 0 100-8 4 4 0 000 8z"/>
</svg>
</div>
<div>
<div style="font-size:26px;font-weight:700;color:#0f172a;line-height:1;" id="stat-total">{{ $stats['total'] }}</div>
<div style="font-size:12px;color:#64748b;margin-top:2px;">Total Suppliers</div>
</div>
</div>
<div style="background:#fff;border-radius:12px;padding:18px 20px;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,.04);display:flex;align-items:center;gap:14px;">
<div style="width:44px;height:44px;border-radius:10px;background:#f0fdf4;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="20" height="20" fill="none" stroke="#16a34a" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
</div>
<div>
<div style="font-size:26px;font-weight:700;color:#16a34a;line-height:1;">{{ $stats['active'] }}</div>
<div style="font-size:12px;color:#64748b;margin-top:2px;">Active</div>
</div>
</div>
<div style="background:#fff;border-radius:12px;padding:18px 20px;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,.04);display:flex;align-items:center;gap:14px;">
<div style="width:44px;height:44px;border-radius:10px;background:#fef2f2;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="20" height="20" fill="none" stroke="#dc2626" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</div>
<div>
<div style="font-size:26px;font-weight:700;color:#dc2626;line-height:1;">{{ $stats['inactive'] }}</div>
<div style="font-size:12px;color:#64748b;margin-top:2px;">Inactive</div>
</div>
</div>
<div style="background:#fff;border-radius:12px;padding:18px 20px;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,.04);display:flex;align-items:center;gap:14px;">
<div style="width:44px;height:44px;border-radius:10px;background:#fefce8;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="20" height="20" fill="none" stroke="#ca8a04" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</div>
<div>
<div style="font-size:26px;font-weight:700;color:#ca8a04;line-height:1;">{{ $stats['categories'] }}</div>
<div style="font-size:12px;color:#64748b;margin-top:2px;">Categories</div>
</div>
</div>
</div>
{{-- ── Search + Count bar ───────────────────────────────────────────────────── --}}
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;gap:12px;">
<div style="position:relative;flex:0 0 auto;">
<svg style="position:absolute;left:11px;top:50%;transform:translateY(-50%);color:#94a3b8;pointer-events:none;"
width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-4.35-4.35M17 11A6 6 0 1 1 5 11a6 6 0 0 1 12 0z"/>
</svg>
<input id="supplier-search"
type="text"
placeholder="Search name, contact, email, phone, address…"
autocomplete="off"
style="padding:8px 14px 8px 34px;border:1px solid #e2e8f0;border-radius:8px;font-size:13.5px;width:340px;outline:none;transition:border-color .15s,box-shadow .15s;">
</div>
<div id="search-count" style="font-size:12.5px;color:#94a3b8;white-space:nowrap;">
{{ $stats['total'] }} suppliers
</div>
</div>
{{-- ── Table ────────────────────────────────────────────────────────────────── --}}
<div style="width:100%;overflow-x:auto;border-radius:12px;border:1px solid #e2e8f0;">
<table id="suppliers-table" style="width:100%;border-collapse:collapse;font-size:12.5px;white-space:nowrap;">
<thead>
<tr style="background:#1e293b;">
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;white-space:nowrap;">Code</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;min-width:200px;white-space:nowrap;">Company</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;white-space:nowrap;">Category</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;min-width:160px;white-space:nowrap;">Contact &amp; Email</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;min-width:140px;white-space:nowrap;">Phone / WhatsApp</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;min-width:140px;white-space:nowrap;">Address</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;white-space:nowrap;">Tax / Credit</th>
<th style="padding:10px 12px;text-align:left;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:#94a3b8;white-space:nowrap;">Status</th>
</tr>
</thead>
<tbody>
@forelse($suppliers as $i => $supplier)
<tr class="supplier-row"
data-supplier='@json($supplier)'
data-update="{{ route('purchase.suppliers.update', $supplier) }}"
data-delete="{{ route('purchase.suppliers.destroy', $supplier) }}"
style="border-bottom:1px solid #f1f5f9;cursor:pointer;{{ $i % 2 === 0 ? '' : 'background:#fafafa;' }}"
onmouseover="this.style.background='#f0f9ff'"
onmouseout="this.style.background='{{ $i % 2 === 0 ? '' : '#fafafa' }}'">
{{-- Code --}}
<td style="padding:10px 12px;font-family:monospace;font-size:11px;color:#94a3b8;vertical-align:top;">
{{ $supplier->supplier_code ?: '—' }}
</td>
{{-- Company + website --}}
<td style="padding:10px 12px;vertical-align:top;max-width:220px;white-space:normal;">
<div style="font-weight:600;color:#0f172a;font-size:13px;line-height:1.3;">{{ $supplier->name }}</div>
@if($supplier->website)
<a href="{{ $supplier->website }}" target="_blank"
style="font-size:11px;color:#2563eb;text-decoration:none;display:block;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px;"
title="{{ $supplier->website }}">
{{ parse_url($supplier->website, PHP_URL_HOST) ?: $supplier->website }}
</a>
@endif
</td>
{{-- Category --}}
<td style="padding:10px 12px;vertical-align:top;">
@if($supplier->category)
<span style="display:inline-block;padding:2px 9px;border-radius:20px;font-size:11px;font-weight:600;background:#f1f5f9;color:#475569;white-space:nowrap;">
{{ $supplier->category }}
</span>
@else
<span style="color:#cbd5e1;"></span>
@endif
</td>
{{-- Contact person + emails stacked --}}
<td style="padding:10px 12px;vertical-align:top;max-width:200px;white-space:normal;">
@if($supplier->contact_person)
<div style="font-weight:500;color:#334155;font-size:12.5px;">{{ $supplier->contact_person }}</div>
@endif
@if($supplier->email)
<a href="mailto:{{ $supplier->email }}"
style="display:block;color:#2563eb;text-decoration:none;font-size:12px;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:190px;"
title="{{ $supplier->email }}">{{ $supplier->email }}</a>
@endif
@if($supplier->secondary_email)
<a href="mailto:{{ $supplier->secondary_email }}"
style="display:block;color:#94a3b8;text-decoration:none;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:190px;"
title="{{ $supplier->secondary_email }}">{{ $supplier->secondary_email }}</a>
@endif
@if(!$supplier->contact_person && !$supplier->email)
<span style="color:#cbd5e1;"></span>
@endif
</td>
{{-- Phones stacked --}}
<td style="padding:10px 12px;vertical-align:top;white-space:nowrap;">
@if($supplier->phone)
<a href="tel:{{ $supplier->phone }}" style="display:block;color:#334155;text-decoration:none;font-size:12.5px;">
{{ $supplier->phone }}
</a>
@endif
@if($supplier->phone2)
<a href="tel:{{ $supplier->phone2 }}" style="display:block;color:#64748b;text-decoration:none;font-size:12px;margin-top:2px;">
{{ $supplier->phone2 }}
</a>
@endif
@if($supplier->whatsapp)
<a href="https://wa.me/{{ ltrim($supplier->whatsapp, '+') }}" target="_blank"
style="display:inline-flex;align-items:center;gap:3px;color:#16a34a;text-decoration:none;font-size:12px;margin-top:2px;">
<svg width="11" height="11" viewBox="0 0 24 24" fill="#16a34a" style="flex-shrink:0;">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/>
</svg>
{{ $supplier->whatsapp }}
</a>
@endif
@if(!$supplier->phone && !$supplier->phone2 && !$supplier->whatsapp)
<span style="color:#cbd5e1;"></span>
@endif
</td>
{{-- Address --}}
<td style="padding:10px 12px;vertical-align:top;color:#475569;max-width:160px;white-space:normal;font-size:12px;line-height:1.4;">
{{ $supplier->address ?: '—' }}
</td>
{{-- Tax + Credit stacked --}}
<td style="padding:10px 12px;vertical-align:top;white-space:nowrap;">
@if($supplier->tax_number)
<div style="font-family:monospace;font-size:11px;color:#64748b;">{{ $supplier->tax_number }}</div>
@endif
@if(in_array(strtolower($supplier->credit_terms ?? ''), ['y','yes']))
<div style="font-size:11px;color:#16a34a;font-weight:600;margin-top:2px;">
Credit{{ $supplier->credit_days ? ' · '.$supplier->credit_days.'d' : '' }}
</div>
@elseif(!$supplier->tax_number)
<span style="color:#cbd5e1;"></span>
@endif
</td>
{{-- Status --}}
<td style="padding:10px 12px;vertical-align:top;">
@if($supplier->is_active)
<span class="badge-green">Active</span>
@else
<span class="badge-gray">Inactive</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="8" style="padding:40px;text-align:center;color:#94a3b8;">No suppliers found.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
{{-- No-results message (shown by JS) --}}
<div id="no-results" style="display:none;text-align:center;padding:40px 20px;color:#94a3b8;font-size:14px;">
No suppliers match your search.
</div>
{{-- ═══════════ Row Context Dropdown ═══════════ --}}
<div id="row-menu" style="display:none;position:fixed;z-index:200;background:#fff;border-radius:12px;
box-shadow:0 8px 30px rgba(0,0,0,.15),0 2px 8px rgba(0,0,0,.08);
border:1px solid #e2e8f0;min-width:190px;padding:6px;overflow:hidden;">
<div id="rm-supplier-label" style="padding:8px 12px 6px;font-size:11px;font-weight:700;
text-transform:uppercase;letter-spacing:.05em;color:#94a3b8;border-bottom:1px solid #f1f5f9;margin-bottom:4px;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:178px;"></div>
<a id="rm-email" href="#" target="_blank"
style="display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:8px;
text-decoration:none;color:#334155;font-size:13px;font-weight:500;">
<span style="width:28px;height:28px;border-radius:8px;background:#eff6ff;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="13" height="13" fill="none" stroke="#2563eb" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
</span>Send Email
</a>
<a id="rm-whatsapp" href="#" target="_blank"
style="display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:8px;
text-decoration:none;color:#334155;font-size:13px;font-weight:500;">
<span style="width:28px;height:28px;border-radius:8px;background:#f0fdf4;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="13" height="13" viewBox="0 0 24 24" fill="#16a34a">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"/>
</svg>
</span>Send WhatsApp
</a>
<div style="height:1px;background:#f1f5f9;margin:4px 0;"></div>
<button id="rm-view" type="button"
style="display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:8px;width:100%;
background:none;border:none;cursor:pointer;color:#334155;font-size:13px;font-weight:500;text-align:left;">
<span style="width:28px;height:28px;border-radius:8px;background:#f8fafc;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="13" height="13" fill="none" stroke="#475569" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
</svg>
</span>View / Edit
</button>
<div style="height:1px;background:#f1f5f9;margin:4px 0;"></div>
<button id="rm-delete" type="button"
style="display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:8px;width:100%;
background:none;border:none;cursor:pointer;color:#dc2626;font-size:13px;font-weight:500;text-align:left;">
<span style="width:28px;height:28px;border-radius:8px;background:#fef2f2;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="13" height="13" fill="none" stroke="#dc2626" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6M1 7h22M8 7V4a1 1 0 011-1h6a1 1 0 011 1v3"/>
</svg>
</span>Delete Supplier
</button>
</div>
{{-- ═══════════ Supplier View / Edit Modal ═══════════ --}}
<datalist id="sm-category-list">
@foreach($categories as $cat)
<option value="{{ $cat }}">
@endforeach
</datalist>
<div id="supplier-modal" style="display:none;position:fixed;inset:0;z-index:250;
background:rgba(15,23,42,.6);backdrop-filter:blur(6px);
align-items:center;justify-content:center;padding:16px;">
<div style="background:#fff;border-radius:20px;width:100%;max-width:640px;
overflow:hidden;display:flex;flex-direction:column;
box-shadow:0 32px 80px rgba(0,0,0,.28);
animation:modalIn .24s cubic-bezier(.34,1.56,.64,1);">
{{-- ── Gradient top stripe ── --}}
<div id="sm-stripe" style="height:3px;background:linear-gradient(90deg,#2563eb 0%,#7c3aed 50%,#0ea5e9 100%);transition:background .3s;"></div>
{{-- ── Header ── --}}
<div style="padding:14px 18px 12px;display:flex;align-items:center;gap:12px;border-bottom:1px solid #f1f5f9;">
{{-- Avatar circle with supplier initial --}}
<div id="sm-avatar" style="width:42px;height:42px;border-radius:12px;flex-shrink:0;
display:flex;align-items:center;justify-content:center;
font-size:18px;font-weight:800;color:#fff;background:linear-gradient(135deg,#2563eb,#7c3aed);
box-shadow:0 4px 10px rgba(37,99,235,.3);">A</div>
<div style="flex:1;min-width:0;">
<div id="sm-hd-name" style="font-size:15px;font-weight:700;color:#0f172a;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:380px;"></div>
<div style="display:flex;align-items:center;gap:6px;margin-top:2px;">
<span id="sm-hd-code" style="font-size:11px;font-family:monospace;color:#94a3b8;"></span>
<span id="sm-hd-cat" style="font-size:11px;color:#7c3aed;font-weight:600;"></span>
</div>
</div>
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0;">
<span id="sm-mode-badge"
style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;
padding:3px 9px;border-radius:20px;background:#f1f5f9;color:#64748b;">View</span>
<button onclick="closeSupplierModal()"
style="width:28px;height:28px;border-radius:8px;background:#f1f5f9;border:none;
cursor:pointer;display:flex;align-items:center;justify-content:center;"
onmouseover="this.style.background='#e2e8f0'" onmouseout="this.style.background='#f1f5f9'">
<svg width="12" height="12" fill="none" stroke="#64748b" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
{{-- ── Form body (scrollable) ── --}}
<form id="supplier-form" method="POST">
@csrf
<input type="hidden" name="_method" id="sm-method-field" value="PUT">
<div style="padding:14px 18px;overflow-y:auto;max-height:calc(100vh - 220px);">
{{-- ·· Row 1: Name + Status toggle ·· --}}
<div style="display:grid;grid-template-columns:1fr auto;gap:10px;align-items:end;margin-bottom:10px;">
<div>
<label class="sm-lbl">Company Name <span style="color:#ef4444;">*</span></label>
<input id="sm-name" name="name" type="text" required class="sm-inp"
style="font-size:14px;font-weight:600;">
</div>
<div>
<label class="sm-lbl">Status</label>
<div id="sm-status-wrap" style="display:flex;border-radius:9px;overflow:hidden;border:1.5px solid #e2e8f0;">
<button id="sm-s-active" type="button" onclick="setSmStatus(1)"
style="padding:7px 14px;border:none;cursor:pointer;font-size:12px;font-weight:600;
display:flex;align-items:center;gap:5px;white-space:nowrap;transition:background .15s,color .15s;">
<span style="width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block;"></span>Active
</button>
<button id="sm-s-inactive" type="button" onclick="setSmStatus(0)"
style="padding:7px 14px;border:none;border-left:1px solid #e2e8f0;cursor:pointer;
font-size:12px;font-weight:600;display:flex;align-items:center;gap:5px;white-space:nowrap;transition:background .15s,color .15s;">
<span style="width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block;"></span>Inactive
</button>
</div>
<input type="hidden" id="sm-active" name="is_active" value="1">
</div>
</div>
{{-- ·· Row 2: Code + Category (datalist) + Website ·· --}}
<div style="display:grid;grid-template-columns:130px 1fr 1fr;gap:10px;margin-bottom:10px;">
<div>
<label class="sm-lbl">Code</label>
<input id="sm-code" name="supplier_code" type="text" class="sm-inp"
style="font-family:monospace;font-size:12px;">
</div>
<div>
<label class="sm-lbl">Category</label>
<input id="sm-category" name="category" type="text" list="sm-category-list"
class="sm-inp" placeholder="Select or type…">
</div>
<div>
<label class="sm-lbl">Website</label>
<input id="sm-website" name="website" type="text" class="sm-inp" placeholder="https://…">
</div>
</div>
{{-- ·· Divider ·· --}}
<div style="display:flex;align-items:center;gap:8px;margin:12px 0 10px;">
<span style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:#cbd5e1;white-space:nowrap;">Contact</span>
<div style="flex:1;height:1px;background:#f1f5f9;"></div>
</div>
{{-- ·· Row 3: Contact + Email + Email2 ·· --}}
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:10px;">
<div>
<label class="sm-lbl">Contact Person</label>
<input id="sm-contact" name="contact_person" type="text" class="sm-inp">
</div>
<div>
<label class="sm-lbl">Primary Email</label>
<input id="sm-email" name="email" type="email" class="sm-inp">
</div>
<div>
<label class="sm-lbl">Secondary Email</label>
<input id="sm-email2" name="secondary_email" type="email" class="sm-inp">
</div>
</div>
{{-- ·· Row 4: Phone + Phone2 + WhatsApp ·· --}}
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:4px;">
<div>
<label class="sm-lbl">Phone 1</label>
<input id="sm-phone" name="phone" type="text" class="sm-inp" style="font-family:monospace;font-size:12px;">
</div>
<div>
<label class="sm-lbl">Phone 2</label>
<input id="sm-phone2" name="phone2" type="text" class="sm-inp" style="font-family:monospace;font-size:12px;">
</div>
<div>
<label class="sm-lbl">WhatsApp</label>
<input id="sm-whatsapp" name="whatsapp" type="text" class="sm-inp" style="font-family:monospace;font-size:12px;">
</div>
</div>
{{-- ·· Divider ·· --}}
<div style="display:flex;align-items:center;gap:8px;margin:12px 0 10px;">
<span style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:#cbd5e1;white-space:nowrap;">Financial</span>
<div style="flex:1;height:1px;background:#f1f5f9;"></div>
</div>
{{-- ·· Row 5: Address + Tax ·· --}}
<div style="display:grid;grid-template-columns:1fr 160px;gap:10px;margin-bottom:10px;">
<div>
<label class="sm-lbl">Address</label>
<input id="sm-address" name="address" type="text" class="sm-inp">
</div>
<div>
<label class="sm-lbl">Tax / VAT Number</label>
<input id="sm-tax" name="tax_number" type="text" class="sm-inp"
style="font-family:monospace;font-size:12px;">
</div>
</div>
{{-- ·· Row 6: Credit toggle + Days + Remarks ·· --}}
<div style="display:grid;grid-template-columns:auto 90px 1fr;gap:10px;align-items:start;">
<div>
<label class="sm-lbl">Credit</label>
<div id="sm-credit-wrap" style="display:flex;border-radius:9px;overflow:hidden;border:1.5px solid #e2e8f0;">
<button id="sm-c-yes" type="button" onclick="setSmCredit('Y')"
style="padding:7px 12px;border:none;cursor:pointer;font-size:12px;font-weight:600;
white-space:nowrap;transition:background .15s,color .15s;">Yes</button>
<button id="sm-c-no" type="button" onclick="setSmCredit('N')"
style="padding:7px 12px;border:none;border-left:1px solid #e2e8f0;cursor:pointer;
font-size:12px;font-weight:600;white-space:nowrap;transition:background .15s,color .15s;">No</button>
</div>
<input type="hidden" id="sm-credit" name="credit_terms" value="">
</div>
<div>
<label class="sm-lbl">Days</label>
<input id="sm-days" name="credit_days" type="number" min="0" class="sm-inp" placeholder="">
</div>
<div>
<label class="sm-lbl">Remarks</label>
<input id="sm-remarks" name="remarks" type="text" class="sm-inp">
</div>
</div>
</div>{{-- end scrollable --}}
{{-- ── Footer ── --}}
<div style="padding:12px 18px 14px;border-top:1px solid #f1f5f9;display:flex;align-items:center;justify-content:space-between;">
<button type="button" onclick="closeSupplierModal()"
style="padding:8px 16px;border-radius:9px;border:1.5px solid #e2e8f0;background:#fff;
font-size:12.5px;font-weight:600;color:#64748b;cursor:pointer;">
Close
</button>
<div style="display:flex;gap:8px;">
<button id="sm-edit-btn" type="button" onclick="enableSupplierEdit()"
style="display:flex;align-items:center;gap:5px;padding:8px 16px;border-radius:9px;
border:1.5px solid #fbbf24;background:#fffbeb;
font-size:12.5px;font-weight:600;color:#92400e;cursor:pointer;">
<svg width="12" height="12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>Edit
</button>
<button id="sm-save-btn" type="submit"
style="display:none;align-items:center;gap:5px;padding:8px 18px;border-radius:9px;
border:none;background:linear-gradient(135deg,#2563eb,#1d4ed8);
font-size:12.5px;font-weight:600;color:#fff;cursor:pointer;
box-shadow:0 3px 10px rgba(37,99,235,.35);">
<svg width="12" height="12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7"/>
</svg><span id="sm-save-label">Save Changes</span>
</button>
</div>
</div>
</form>
</div>
</div>
{{-- ═══════════ Delete Confirmation Modal ═══════════ --}}
<div id="delete-modal" style="display:none;position:fixed;inset:0;z-index:300;
background:rgba(15,23,42,.7);backdrop-filter:blur(6px);
display:none;align-items:center;justify-content:center;padding:20px;">
<div style="background:#fff;border-radius:20px;width:100%;max-width:420px;overflow:hidden;
box-shadow:0 30px 80px rgba(0,0,0,.3);
animation:modalIn .25s cubic-bezier(.34,1.56,.64,1);">
{{-- Red danger header --}}
<div style="background:linear-gradient(135deg,#991b1b 0%,#dc2626 60%,#ef4444 100%);padding:24px 24px 20px;">
<div style="display:flex;align-items:center;gap:12px;">
<div style="width:44px;height:44px;border-radius:14px;background:rgba(255,255,255,.15);
display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="22" height="22" fill="none" stroke="#fff" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/>
</svg>
</div>
<div>
<h2 style="color:#fff;font-size:16px;font-weight:700;line-height:1.2;">Permanent Deletion</h2>
<p style="color:rgba(255,255,255,.65);font-size:12px;margin-top:2px;">This action cannot be undone</p>
</div>
</div>
</div>
<div style="padding:22px 24px;">
<p style="font-size:14px;color:#334155;line-height:1.6;margin-bottom:6px;">
You are about to permanently delete:
</p>
<div id="del-supplier-name"
style="font-size:14px;font-weight:700;color:#0f172a;background:#fef2f2;
border:1px solid #fecaca;border-radius:8px;padding:10px 14px;
margin-bottom:18px;word-break:break-word;"></div>
<p style="font-size:13px;color:#64748b;margin-bottom:6px;line-height:1.5;">
All purchase orders, invoices, and payment records linked to this supplier may be affected.
To confirm, type the supplier name exactly as shown above:
</p>
<input id="del-confirm-input" type="text" autocomplete="off" spellcheck="false"
placeholder="Type supplier name to confirm…"
style="width:100%;padding:10px 14px;border:2px solid #e2e8f0;border-radius:10px;
font-size:13px;outline:none;transition:border-color .15s,box-shadow .15s;box-sizing:border-box;">
<div id="del-match-hint" style="font-size:11.5px;margin-top:6px;height:16px;color:#94a3b8;"></div>
</div>
<div style="display:flex;gap:10px;padding:0 24px 22px;">
<button type="button" onclick="closeDeleteModal()"
style="flex:1;padding:11px;border-radius:10px;border:1.5px solid #e2e8f0;
background:#fff;font-size:13.5px;font-weight:600;color:#475569;cursor:pointer;">
Cancel Keep Supplier
</button>
<form id="delete-form" method="POST" style="flex:1;">
@csrf
@method('DELETE')
<button id="del-confirm-btn" type="submit" disabled
style="width:100%;padding:11px;border-radius:10px;border:none;
background:#e2e8f0;font-size:13.5px;font-weight:600;
color:#94a3b8;cursor:not-allowed;transition:background .2s,color .2s;">
Yes, Delete Permanently
</button>
</form>
</div>
</div>
</div>
{{-- ═══════════ Import Modal ═══════════ --}}
<div id="import-modal"
class="hidden fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4"
style="background:rgba(15,23,42,.6); backdrop-filter:blur(4px);">
<div style="background:#fff;border-radius:18px;box-shadow:0 25px 60px rgba(0,0,0,.25);
width:100%;max-width:480px;overflow:hidden;
animation:modalIn .22s cubic-bezier(.34,1.56,.64,1);">
<div style="background:linear-gradient(135deg,#1d4ed8 0%,#2563eb 60%,#3b82f6 100%); padding:22px 24px 20px;">
<div class="flex items-start justify-between">
<div class="flex items-center gap-3">
<div style="width:40px;height:40px;border-radius:12px;background:rgba(255,255,255,.15);display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<svg width="20" height="20" fill="none" stroke="#fff" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 17v-2m3 2v-4m3 4v-6M3 21h18M3 10l9-7 9 7M5 21V10"/>
</svg>
</div>
<div>
<h2 style="color:#fff;font-size:15px;font-weight:700;line-height:1.2;">Import Suppliers</h2>
<p style="color:rgba(255,255,255,.65);font-size:12px;margin-top:2px;">Upload an Excel file to add suppliers in bulk</p>
</div>
</div>
<button onclick="closeImportModal()"
style="width:30px;height:30px;border-radius:8px;background:rgba(255,255,255,.12);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;"
onmouseover="this.style.background='rgba(255,255,255,.22)'"
onmouseout="this.style.background='rgba(255,255,255,.12)'">
<svg width="14" height="14" fill="none" stroke="#fff" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
<form action="{{ route('purchase.suppliers.import') }}" method="POST" enctype="multipart/form-data">
@csrf
<div style="padding:20px 24px 0;">
<label for="import-file" id="drop-zone"
ondragover="event.preventDefault(); dzActivate()"
ondragleave="dzDeactivate()"
ondrop="handleDrop(event)"
style="display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;
padding:28px 20px;border-radius:14px;cursor:pointer;
border:2px dashed #cbd5e1;background:#f8fafc;transition:border-color .15s,background .15s;">
<div id="dz-icon" style="width:48px;height:48px;border-radius:12px;background:#dcfce7;display:flex;align-items:center;justify-content:center;transition:transform .2s;">
<svg width="24" height="24" fill="none" viewBox="0 0 24 24">
<rect x="3" y="3" width="18" height="18" rx="3" fill="#16a34a"/>
<path d="M8 8l2.5 4L8 16h1.8l1.7-2.8L13.2 16H15l-2.5-4 2.5-4h-1.8l-1.7 2.8L9.8 8H8z" fill="#fff"/>
</svg>
</div>
<div id="dz-idle" style="text-align:center;">
<p style="font-size:13.5px;font-weight:600;color:#334155;">Drop your Excel file here</p>
<p style="font-size:12px;color:#94a3b8;margin-top:3px;">or <span style="color:#2563eb;font-weight:600;">browse files</span></p>
<p style="font-size:11px;color:#cbd5e1;margin-top:5px;">.xlsx &nbsp;·&nbsp; .xls &nbsp;·&nbsp; max 10 MB</p>
</div>
<div id="dz-selected" style="display:none;text-align:center;">
<p id="dz-filename" style="font-size:13px;font-weight:700;color:#1e293b;word-break:break-all;"></p>
<p style="font-size:11px;color:#64748b;margin-top:4px;">
<span id="dz-filesize"></span> &nbsp;·&nbsp; <span style="color:#2563eb;font-weight:500;">Change file</span>
</p>
</div>
<input id="import-file" type="file" name="file" accept=".xlsx,.xls" class="sr-only" onchange="handleFileSelect(this)">
</label>
</div>
<div style="margin:14px 24px 0;padding:10px 14px;border-radius:10px;background:#f8fafc;border:1px solid #e2e8f0;">
<p style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#94a3b8;margin-bottom:8px;">Accepted formats</p>
<div style="display:flex;gap:6px;flex-wrap:wrap;">
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:20px;background:#eff6ff;border:1px solid #bfdbfe;font-size:11px;font-weight:600;color:#1d4ed8;">
<span style="width:5px;height:5px;border-radius:50%;background:#2563eb;display:inline-block;"></span>MRF Comparison
</span>
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:20px;background:#f0fdf4;border:1px solid #bbf7d0;font-size:11px;font-weight:600;color:#15803d;">
<span style="width:5px;height:5px;border-radius:50%;background:#16a34a;display:inline-block;"></span>Standard Template
</span>
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:20px;background:#fefce8;border:1px solid #fde68a;font-size:11px;font-weight:600;color:#92400e;">
<span style="width:5px;height:5px;border-radius:50%;background:#ca8a04;display:inline-block;"></span>Duplicates skipped
</span>
</div>
</div>
<div style="height:20px;"></div>
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 24px 20px;border-top:1px solid #f1f5f9;">
<a href="{{ route('purchase.suppliers.template') }}"
style="display:inline-flex;align-items:center;gap:5px;font-size:12px;color:#64748b;text-decoration:none;font-weight:500;"
onmouseover="this.style.color='#2563eb'" onmouseout="this.style.color='#64748b'">
<svg width="13" height="13" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
</svg>
Download template
</a>
<div style="display:flex;gap:8px;">
<button type="button" onclick="closeImportModal()" class="btn-secondary">Cancel</button>
<button type="submit" id="import-submit-btn" class="btn-primary" disabled
style="opacity:.45;cursor:not-allowed;">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
</svg>
Import Suppliers
</button>
</div>
</div>
</form>
</div>
</div>
<style>
@keyframes modalIn {
from { opacity:0; transform:scale(.94) translateY(10px); }
to { opacity:1; transform:scale(1) translateY(0); }
}
@keyframes menuIn {
from { opacity:0; transform:scale(.95) translateY(-6px); }
to { opacity:1; transform:scale(1) translateY(0); }
}
#drop-zone:hover { border-color:#93c5fd !important; background:#eff6ff !important; }
#drop-zone.dz-active { border-color:#2563eb !important; background:#eff6ff !important; }
#drop-zone.dz-active #dz-icon { transform:scale(1.1); }
#drop-zone.dz-has-file { border-color:#4ade80 !important; background:#f0fdf4 !important; }
#supplier-search:focus { border-color:#2563eb !important; box-shadow:0 0 0 3px rgba(37,99,235,.12); }
.supplier-row.hidden-by-search { display:none; }
#row-menu a:hover, #row-menu button:hover { background:#f8fafc !important; }
#row-menu #rm-delete:hover { background:#fef2f2 !important; }
#delete-modal.open { display:flex !important; }
#supplier-modal.open { display:flex !important; }
/* Shared label / input styles used in the supplier modal */
.sm-lbl {
display:block;font-size:10.5px;font-weight:600;
color:#64748b;text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px;
}
.sm-inp {
width:100%;padding:7px 11px;border:1.5px solid #e2e8f0;border-radius:8px;
font-size:13px;outline:none;box-sizing:border-box;transition:border-color .15s,background .15s,color .15s;
}
/* View mode */
#supplier-form.view .sm-inp {
background:#f8fafc;color:#334155;border-color:#f1f5f9;cursor:default;
}
/* Edit mode */
#supplier-form.edit .sm-inp:focus {
border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.1);
}
</style>
<script>
// ══════════════════════════════════════════════════════════
// Import modal
// ══════════════════════════════════════════════════════════
function closeImportModal() { document.getElementById('import-modal').classList.add('hidden'); }
function dzActivate() { document.getElementById('drop-zone').classList.add('dz-active'); }
function dzDeactivate() { document.getElementById('drop-zone').classList.remove('dz-active'); }
function formatBytes(b) {
return b < 1024 ? b+' B' : b < 1048576 ? (b/1024).toFixed(1)+' KB' : (b/1048576).toFixed(1)+' MB';
}
function applyFile(file) {
var zone = document.getElementById('drop-zone');
zone.classList.remove('dz-active'); zone.classList.add('dz-has-file');
document.getElementById('dz-idle').style.display = 'none';
document.getElementById('dz-selected').style.display = 'block';
document.getElementById('dz-filename').textContent = file.name;
document.getElementById('dz-filesize').textContent = formatBytes(file.size);
var btn = document.getElementById('import-submit-btn');
btn.disabled = false; btn.style.opacity = '1'; btn.style.cursor = 'pointer';
}
function handleFileSelect(input) { if (input.files.length) applyFile(input.files[0]); }
function handleDrop(e) {
e.preventDefault(); dzDeactivate();
var file = e.dataTransfer.files[0]; if (!file) return;
var input = document.getElementById('import-file');
var dt = new DataTransfer(); dt.items.add(file); input.files = dt.files;
applyFile(file);
}
document.getElementById('import-modal').addEventListener('click', function(e) {
if (e.target === this) closeImportModal();
});
// ══════════════════════════════════════════════════════════
// Supplier view / edit / create modal
// ══════════════════════════════════════════════════════════
var _smIsEdit = false;
var _smStoreUrl = '{{ route("purchase.suppliers.store") }}';
// Colour palette for avatar (cycles by first char code)
var _avatarColors = [
'linear-gradient(135deg,#2563eb,#7c3aed)',
'linear-gradient(135deg,#0ea5e9,#2563eb)',
'linear-gradient(135deg,#7c3aed,#db2777)',
'linear-gradient(135deg,#16a34a,#0ea5e9)',
'linear-gradient(135deg,#ea580c,#dc2626)',
'linear-gradient(135deg,#0891b2,#7c3aed)',
];
function _avatarGrad(name) {
return _avatarColors[(name.charCodeAt(0) || 0) % _avatarColors.length];
}
function _smSetToggle(activeId, inactiveId, activeStyles, inactiveStyles, selectedId) {
var a = document.getElementById(activeId), b = document.getElementById(inactiveId);
var sel = selectedId === activeId ? a : b;
var unsel = sel === a ? b : a;
Object.assign(sel.style, activeStyles);
Object.assign(unsel.style, inactiveStyles);
}
function setSmStatus(val) {
if (!_smIsEdit) return;
document.getElementById('sm-active').value = val;
var on = { background:'#dcfce7', color:'#15803d' };
var off = { background:'#f8fafc', color:'#94a3b8' };
if (val == 1) {
Object.assign(document.getElementById('sm-s-active').style, on);
Object.assign(document.getElementById('sm-s-inactive').style, off);
} else {
Object.assign(document.getElementById('sm-s-active').style, off);
Object.assign(document.getElementById('sm-s-inactive').style, { background:'#fef2f2', color:'#dc2626' });
}
}
function _renderStatus(val) {
// Force-render status toggle without _smIsEdit guard
var was = _smIsEdit; _smIsEdit = true; setSmStatus(val); _smIsEdit = was;
}
function setSmCredit(val) {
if (!_smIsEdit) return;
document.getElementById('sm-credit').value = val;
var yes = document.getElementById('sm-c-yes'), no = document.getElementById('sm-c-no');
var neutral = { background:'#f8fafc', color:'#94a3b8' };
if (val === 'Y') {
Object.assign(yes.style, { background:'#dcfce7', color:'#15803d' });
Object.assign(no.style, neutral);
} else if (val === 'N') {
Object.assign(no.style, { background:'#fef2f2', color:'#dc2626' });
Object.assign(yes.style, neutral);
} else {
Object.assign(yes.style, neutral); Object.assign(no.style, neutral);
}
}
function _renderCredit(val) {
var was = _smIsEdit; _smIsEdit = true; setSmCredit(val); _smIsEdit = was;
}
function openSupplierModal(s, updateUrl, mode) {
// Header identity
var initial = (s.name || '?').charAt(0).toUpperCase();
var avatar = document.getElementById('sm-avatar');
avatar.textContent = initial;
avatar.style.background = _avatarGrad(s.name || '');
document.getElementById('sm-hd-name').textContent = s.name || '';
document.getElementById('sm-hd-code').textContent = s.supplier_code ? s.supplier_code : '';
document.getElementById('sm-hd-cat').textContent = s.category ? '· ' + s.category : '';
// Fields
document.getElementById('sm-code').value = s.supplier_code || '';
document.getElementById('sm-name').value = s.name || '';
document.getElementById('sm-category').value = s.category || '';
document.getElementById('sm-website').value = s.website || '';
document.getElementById('sm-contact').value = s.contact_person || '';
document.getElementById('sm-email').value = s.email || '';
document.getElementById('sm-email2').value = s.secondary_email|| '';
document.getElementById('sm-phone').value = s.phone || '';
document.getElementById('sm-phone2').value = s.phone2 || '';
document.getElementById('sm-whatsapp').value = s.whatsapp || '';
document.getElementById('sm-address').value = s.address || '';
document.getElementById('sm-tax').value = s.tax_number || '';
document.getElementById('sm-days').value = s.credit_days != null ? s.credit_days : '';
document.getElementById('sm-remarks').value = s.remarks || '';
// Toggles (render without edit guard)
_renderStatus(s.is_active ? 1 : 0);
var ct = (s.credit_terms || '').toUpperCase();
_renderCredit(ct === 'Y' || ct === 'YES' ? 'Y' : ct === 'N' || ct === 'NO' ? 'N' : '');
document.getElementById('supplier-form').action = updateUrl;
setSupplierMode(mode);
document.getElementById('supplier-modal').classList.add('open');
}
function openNewSupplierModal() {
// Avatar — plus icon style
var avatar = document.getElementById('sm-avatar');
avatar.textContent = '+';
avatar.style.background = 'linear-gradient(135deg,#16a34a,#059669)';
avatar.style.boxShadow = '0 4px 10px rgba(22,163,74,.3)';
document.getElementById('sm-hd-name').textContent = 'New Supplier';
document.getElementById('sm-hd-code').textContent = '';
document.getElementById('sm-hd-cat').textContent = '';
// Clear every field
['sm-code','sm-name','sm-category','sm-website','sm-contact',
'sm-email','sm-email2','sm-phone','sm-phone2','sm-whatsapp',
'sm-address','sm-tax','sm-days','sm-remarks'].forEach(function(id) {
document.getElementById(id).value = '';
});
// Default toggles
_renderStatus(1); // Active by default
_renderCredit(''); // Credit unset
// Form targets the store (POST) route — disable the _method override
document.getElementById('supplier-form').action = _smStoreUrl;
document.getElementById('sm-method-field').disabled = true;
setSupplierMode('create');
document.getElementById('supplier-modal').classList.add('open');
setTimeout(function() { document.getElementById('sm-name').focus(); }, 80);
}
function setSupplierMode(mode) {
_smIsEdit = (mode === 'edit' || mode === 'create');
var isCreate = mode === 'create';
var form = document.getElementById('supplier-form');
var inputs = form.querySelectorAll('input:not([type=hidden]):not([disabled~=permanent]), select, textarea');
form.classList.toggle('view', mode === 'view');
form.classList.toggle('edit', _smIsEdit);
inputs.forEach(function(el) {
if (_smIsEdit) el.removeAttribute('disabled');
else el.setAttribute('disabled', '');
});
// Toggles
document.getElementById('sm-status-wrap').style.pointerEvents = _smIsEdit ? '' : 'none';
document.getElementById('sm-credit-wrap').style.pointerEvents = _smIsEdit ? '' : 'none';
// Mode badge
var badge = document.getElementById('sm-mode-badge');
var badgeCfg = {
view: { text:'View', bg:'#f1f5f9', color:'#64748b' },
edit: { text:'Editing', bg:'#fffbeb', color:'#92400e' },
create: { text:'New', bg:'#f0fdf4', color:'#15803d' },
}[mode];
badge.textContent = badgeCfg.text;
badge.style.background = badgeCfg.bg;
badge.style.color = badgeCfg.color;
// Top stripe colour
var stripes = {
view: 'linear-gradient(90deg,#2563eb,#7c3aed,#0ea5e9)',
edit: 'linear-gradient(90deg,#f59e0b,#d97706,#b45309)',
create: 'linear-gradient(90deg,#16a34a,#059669,#0ea5e9)',
};
document.getElementById('sm-stripe').style.background = stripes[mode];
// Save button label & colour
var saveBtn = document.getElementById('sm-save-btn');
document.getElementById('sm-save-label').textContent = isCreate ? 'Add Supplier' : 'Save Changes';
saveBtn.style.background = isCreate
? 'linear-gradient(135deg,#16a34a,#059669)'
: 'linear-gradient(135deg,#2563eb,#1d4ed8)';
saveBtn.style.boxShadow = isCreate
? '0 3px 10px rgba(22,163,74,.35)'
: '0 3px 10px rgba(37,99,235,.35)';
// Show/hide footer buttons
document.getElementById('sm-edit-btn').style.display = (mode === 'view') ? 'flex' : 'none';
saveBtn.style.display = _smIsEdit ? 'flex' : 'none';
// Restore method field for edit mode
if (!isCreate) {
document.getElementById('sm-method-field').disabled = false;
document.getElementById('sm-method-field').value = 'PUT';
}
}
function enableSupplierEdit() { setSupplierMode('edit'); }
function closeSupplierModal() {
document.getElementById('supplier-modal').classList.remove('open');
}
document.getElementById('supplier-modal').addEventListener('click', function(e) {
if (e.target === this) closeSupplierModal();
});
// ══════════════════════════════════════════════════════════
// Row context menu
// ══════════════════════════════════════════════════════════
(function () {
var menu = document.getElementById('row-menu');
var current = null;
function closeMenu() {
menu.style.display = 'none';
current = null;
}
function openMenu(row, x, y) {
var s = JSON.parse(row.dataset.supplier);
var delUrl = row.dataset.delete;
var updUrl = row.dataset.update;
var email = s.email;
var waNum = s.whatsapp || s.phone;
document.getElementById('rm-supplier-label').textContent = s.name;
var rmEmail = document.getElementById('rm-email');
if (email) {
rmEmail.href = 'mailto:' + email;
rmEmail.style.opacity = '1'; rmEmail.style.pointerEvents = '';
} else {
rmEmail.href = '#'; rmEmail.style.opacity = '.35'; rmEmail.style.pointerEvents = 'none';
}
var rmWa = document.getElementById('rm-whatsapp');
if (waNum) {
rmWa.href = 'https://wa.me/' + waNum.replace(/[^0-9]/g, '');
rmWa.style.opacity = '1'; rmWa.style.pointerEvents = '';
} else {
rmWa.href = '#'; rmWa.style.opacity = '.35'; rmWa.style.pointerEvents = 'none';
}
document.getElementById('rm-view').onclick = function() {
closeMenu(); openSupplierModal(s, updUrl, 'view');
};
document.getElementById('rm-delete').onclick = function() {
closeMenu(); openDeleteModal(s.name, delUrl);
};
menu.style.display = 'block';
menu.style.animation = 'menuIn .18s cubic-bezier(.34,1.56,.64,1)';
var mw = menu.offsetWidth, mh = menu.offsetHeight;
var vw = window.innerWidth, vh = window.innerHeight;
var left = x + 4, top = y + 4;
if (left + mw > vw - 10) left = vw - mw - 10;
if (top + mh > vh - 10) top = y - mh - 4;
menu.style.left = left + 'px'; menu.style.top = top + 'px';
current = row;
}
document.querySelectorAll('.supplier-row').forEach(function(row) {
row.addEventListener('click', function(e) {
if (e.target.closest('a, button, form')) return;
e.stopPropagation();
if (current === row && menu.style.display !== 'none') { closeMenu(); return; }
closeMenu();
openMenu(row, e.clientX, e.clientY);
});
});
document.addEventListener('click', function(e) {
if (!menu.contains(e.target)) closeMenu();
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') { closeMenu(); closeDeleteModal(); closeSupplierModal(); closeImportModal(); }
});
})();
// ══════════════════════════════════════════════════════════
// Delete confirmation modal
// ══════════════════════════════════════════════════════════
var _delExpected = '';
function openDeleteModal(name, actionUrl) {
_delExpected = name;
document.getElementById('del-supplier-name').textContent = name;
var inp = document.getElementById('del-confirm-input');
inp.value = ''; inp.style.borderColor = '#e2e8f0';
document.getElementById('del-match-hint').textContent = '';
var btn = document.getElementById('del-confirm-btn');
btn.disabled = true; btn.style.background = '#e2e8f0'; btn.style.color = '#94a3b8'; btn.style.cursor = 'not-allowed';
document.getElementById('delete-form').action = actionUrl;
document.getElementById('delete-modal').classList.add('open');
setTimeout(function() { inp.focus(); }, 80);
}
function closeDeleteModal() { document.getElementById('delete-modal').classList.remove('open'); }
document.getElementById('del-confirm-input').addEventListener('input', function() {
var btn = document.getElementById('del-confirm-btn');
var hint = document.getElementById('del-match-hint');
if (this.value === _delExpected) {
btn.disabled = false; btn.style.background = '#dc2626'; btn.style.color = '#fff'; btn.style.cursor = 'pointer';
hint.textContent = '✓ Name matches — you may now confirm deletion.'; hint.style.color = '#16a34a';
this.style.borderColor = '#4ade80';
} else {
btn.disabled = true; btn.style.background = '#e2e8f0'; btn.style.color = '#94a3b8'; btn.style.cursor = 'not-allowed';
if (this.value.length > 0) { hint.textContent = 'Name does not match yet…'; hint.style.color = '#f59e0b'; this.style.borderColor = '#fbbf24'; }
else { hint.textContent = ''; this.style.borderColor = '#e2e8f0'; }
}
});
document.getElementById('delete-modal').addEventListener('click', function(e) {
if (e.target === this) closeDeleteModal();
});
// ══════════════════════════════════════════════════════════
// Live search (client-side, no page reload)
// ══════════════════════════════════════════════════════════
(function () {
var searchInput = document.getElementById('supplier-search');
var countEl = document.getElementById('search-count');
var noResults = document.getElementById('no-results');
var rows = document.querySelectorAll('.supplier-row');
var total = rows.length;
searchInput.addEventListener('input', function() {
var q = this.value.trim().toLowerCase(), visible = 0;
rows.forEach(function(row) {
var text = row.textContent.toLowerCase();
if (!q || text.indexOf(q) !== -1) { row.classList.remove('hidden-by-search'); visible++; }
else { row.classList.add('hidden-by-search'); }
});
countEl.textContent = q ? (visible + ' of ' + total + ' suppliers') : (total + ' suppliers');
noResults.style.display = (visible === 0 && q) ? 'block' : 'none';
});
searchInput.focus();
})();
</script>
@endsection