From c548c0dce39cb032060f67c7bf773ba25b2fd257 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Mon, 19 Oct 2026 16:27:17 +0530 Subject: [PATCH] Fix WASA security observations: security headers, CSP hardening, JS library updates, API authentication, and data scrubbing --- app/Config/Filters.php | 2 + app/Config/Routes.php | 2 +- app/Controllers/Api/v1/DoctorApi.php | 69 +- app/Controllers/Api/v1/NursingApi.php | 75 +- app/Filters/ApiAuthFilter.php | 148 + app/Filters/SecureHeadersFilter.php | 20 +- .../Invoice/Organization_invoice_print_v.php | 6 - app/Views/org_packing/create.php | 6 +- app/Views/org_packing/edit.php | 6 +- app/Views/org_packing/index.php | 6 +- app/Views/org_packing/print_ipd.php | 4 +- app/Views/org_packing/print_opd.php | 4 +- app/Views/welcome_message.php | 2 +- public/App/Doctor/doctor-app.bundle.js | 2392 ++ public/App/Doctor/index.html | 1595 +- public/App/MedicalStore/index.html | 15310 +----------- .../MedicalStore/medicalstore-app.bundle.js | 20275 ++++++++++++++++ public/App/Nursing/index.html | 2988 +-- public/App/Nursing/nursing-app.bundle.js | 4540 ++++ .../assets/vendor/jquery/jquery-3.7.1.min.js | 2 + public/assets/vendor/select2/select2.min.css | 2 +- public/assets/vendor/select2/select2.min.js | 5 +- scripts/build_pwas.js | 76 + scripts/switch_to_bundles.js | 41 + 24 files changed, 27656 insertions(+), 19920 deletions(-) create mode 100644 app/Filters/ApiAuthFilter.php create mode 100644 public/App/Doctor/doctor-app.bundle.js create mode 100644 public/App/MedicalStore/medicalstore-app.bundle.js create mode 100644 public/App/Nursing/nursing-app.bundle.js create mode 100644 public/assets/vendor/jquery/jquery-3.7.1.min.js create mode 100644 scripts/build_pwas.js create mode 100644 scripts/switch_to_bundles.js diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 31dd8ac..4d53260 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -2,6 +2,7 @@ namespace Config; +use App\Filters\ApiAuthFilter; use App\Filters\SecureHeadersFilter; use App\Filters\SingleActiveSessionFilter; use CodeIgniter\Config\Filters as BaseFilters; @@ -37,6 +38,7 @@ class Filters extends BaseFilters 'pagecache' => PageCache::class, 'performance' => PerformanceMetrics::class, 'singleSession' => SingleActiveSessionFilter::class, + 'apiAuth' => ApiAuthFilter::class, ]; /** diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 96e8c06..e628609 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -1676,7 +1676,7 @@ $routes->match(['GET', 'HEAD'], 'app/queue/manifest.json', 'Api\v1\DoctorApi::qu $routes->match(['GET', 'HEAD'], 'app/queue/(:any)', 'Api\v1\DoctorApi::queueIndex'); // Dedicated RESTful JSON API v1 Group for React PWAs & Mobile Apps -$routes->group('api/v1', ['namespace' => 'App\Controllers\Api\v1'], static function ($routes) { +$routes->group('api/v1', ['namespace' => 'App\Controllers\Api\v1', 'filter' => 'apiAuth'], static function ($routes) { // Live TV Queue Display API $routes->get('opd/queue/live', 'DoctorApi::liveQueueDisplay'); // Nursing PWA APIs diff --git a/app/Controllers/Api/v1/DoctorApi.php b/app/Controllers/Api/v1/DoctorApi.php index 2a89a07..7030c0a 100644 --- a/app/Controllers/Api/v1/DoctorApi.php +++ b/app/Controllers/Api/v1/DoctorApi.php @@ -49,18 +49,25 @@ class DoctorApi extends BaseController /** * GET api/v1/doctor/list - * Returns sanitized doctor list for UI pickers (Data Minimized: PII and signatures stripped) + * Returns sanitized doctor list for authorized users only (All Sensitive/Auth Fields Scrubbed) */ public function doctors() { + if (! $this->isAuthenticatedDoctorOrUser()) { + return $this->response->setStatusCode(401)->setJSON([ + 'status' => 0, + 'message' => 'Unauthorized access. Authentication is required to view doctor directory.', + ]); + } + $doctors = $this->doctorModel->getDoctors(); $list = []; foreach ($doctors as $d) { + $name = trim(($d->p_title ?? '') . ' ' . ($d->p_fname ?? '') . ' ' . ($d->p_lname ?? '')); $list[] = [ 'id' => (int) $d->id, - 'name' => trim(($d->p_title ?? '') . ' ' . ($d->p_fname ?? '')), + 'name' => $name, 'department' => $d->department ?? '', - 'has_pin' => ! empty($d->app_pin), ]; } @@ -70,6 +77,61 @@ class DoctorApi extends BaseController ]); } + /** + * Helper to verify if the requesting client has an active authenticated session or valid token + */ + protected function isAuthenticatedDoctorOrUser(): bool + { + if (function_exists('auth') && auth()->loggedIn()) { + return true; + } + + $session = session(); + if ($session->has('user_id') && (int) $session->get('user_id') > 0) { + return true; + } + + if ($session->has('pwa_auth_doctor_id') && (int) $session->get('pwa_auth_doctor_id') > 0) { + return true; + } + + if ($session->has('pwa_auth_nurse_id') && (int) $session->get('pwa_auth_nurse_id') > 0) { + return true; + } + + $token = trim((string) $this->request->getHeaderLine('X-Device-Token')); + if ($token === '') { + $authHeader = trim((string) $this->request->getHeaderLine('Authorization')); + if (preg_match('/Bearer\s+([a-f0-9]{64})/i', $authHeader, $matches)) { + $token = $matches[1]; + } + } + if ($token === '') { + $token = trim((string) ($this->request->getGet('device_token') ?? $this->request->getPost('device_token') ?? '')); + } + + if ($token !== '' && strlen($token) === 64) { + if (service('cache')->get('api_device_token_' . $token)) { + return true; + } + $doctors = db_connect()->table('doctor_master') + ->select('id, device_code') + ->where('active', 1) + ->where('device_code IS NOT NULL') + ->where('device_code !=', '') + ->get()->getResultArray(); + foreach ($doctors as $doc) { + $expected = hash_hmac('sha256', (string) $doc['id'], (string) $doc['device_code']); + if (hash_equals($expected, $token)) { + service('cache')->save('api_device_token_' . $token, ['role' => 'doctor', 'id' => (int) $doc['id']], 86400 * 30); + return true; + } + } + } + + return false; + } + private function isHospitalIntranet(string $ip): bool { if (in_array($ip, ['127.0.0.1', '::1', 'localhost'], true)) { @@ -248,6 +310,7 @@ class DoctorApi extends BaseController if (session_status() === PHP_SESSION_ACTIVE || ! session_id()) { session()->set('pwa_auth_doctor_id', (int) $doctorRow->id); } + service('cache')->save('api_device_token_' . $expectedDeviceToken, ['role' => 'doctor', 'id' => (int) $doctorRow->id], 86400 * 30); return $this->response->setJSON([ 'status' => 1, diff --git a/app/Controllers/Api/v1/NursingApi.php b/app/Controllers/Api/v1/NursingApi.php index d980bd7..681bc9b 100644 --- a/app/Controllers/Api/v1/NursingApi.php +++ b/app/Controllers/Api/v1/NursingApi.php @@ -68,6 +68,13 @@ class NursingApi extends BaseController */ public function beds() { + if (! $this->isAuthenticatedNurseOrUser()) { + return $this->response->setStatusCode(401)->setJSON([ + 'status' => 0, + 'message' => 'Unauthorized access. Authentication is required to view hospital bed records.', + ]); + } + $db = db_connect(); $sql = "SELECT b.id, b.bed_number, b.bed_code, b.bed_category_id, b.ward_id, b.current_ipd_id, b.status, coalesce(b.bed_status, 'available') as bed_status, @@ -106,10 +113,17 @@ class NursingApi extends BaseController /** * GET api/v1/nursing/nurses - * Returns sanitized active nurse staff list for PWA staff switcher (Data Minimized & Credentials Stripped) + * Returns sanitized active nurse staff list for authorized users only (All Sensitive/Auth Fields Scrubbed) */ public function nurses() { + if (! $this->isAuthenticatedNurseOrUser()) { + return $this->response->setStatusCode(401)->setJSON([ + 'status' => 0, + 'message' => 'Unauthorized access. Authentication is required to view nursing staff data.', + ]); + } + $nurses = $this->nurseModel->getActiveNurses(); $safeList = []; foreach ($nurses as $n) { @@ -117,11 +131,8 @@ class NursingApi extends BaseController 'id' => (int) ($n['id'] ?? 0), 'nurse_code' => (string) ($n['nurse_code'] ?? ''), 'name' => (string) ($n['name'] ?? ''), - 'gender' => (string) ($n['gender'] ?? ''), 'designation' => (string) ($n['designation'] ?? 'Staff Nurse'), 'department' => (string) ($n['department'] ?? 'Nursing'), - 'has_pin' => ! empty($n['app_pin']), - 'is_active' => (int) ($n['is_active'] ?? 1), ]; } @@ -131,6 +142,61 @@ class NursingApi extends BaseController ]); } + /** + * Helper to verify if the requesting client has an active authenticated session or valid token + */ + protected function isAuthenticatedNurseOrUser(): bool + { + if (function_exists('auth') && auth()->loggedIn()) { + return true; + } + + $session = session(); + if ($session->has('user_id') && (int) $session->get('user_id') > 0) { + return true; + } + + if ($session->has('pwa_auth_nurse_id') && (int) $session->get('pwa_auth_nurse_id') > 0) { + return true; + } + + if ($session->has('pwa_auth_doctor_id') && (int) $session->get('pwa_auth_doctor_id') > 0) { + return true; + } + + $token = trim((string) $this->request->getHeaderLine('X-Device-Token')); + if ($token === '') { + $authHeader = trim((string) $this->request->getHeaderLine('Authorization')); + if (preg_match('/Bearer\s+([a-f0-9]{64})/i', $authHeader, $matches)) { + $token = $matches[1]; + } + } + if ($token === '') { + $token = trim((string) ($this->request->getGet('device_token') ?? $this->request->getPost('device_token') ?? '')); + } + + if ($token !== '' && strlen($token) === 64) { + if (service('cache')->get('api_device_token_' . $token)) { + return true; + } + $nurses = db_connect()->table('nurse_master') + ->select('id, nurse_code, device_code') + ->where('is_active', 1) + ->where('device_code IS NOT NULL') + ->where('device_code !=', '') + ->get()->getResultArray(); + foreach ($nurses as $nurse) { + $expected = hash_hmac('sha256', $nurse['id'] . '_' . ($nurse['nurse_code'] ?? ''), (string) $nurse['device_code']); + if (hash_equals($expected, $token)) { + service('cache')->save('api_device_token_' . $token, ['role' => 'nurse', 'id' => (int) $nurse['id']], 86400 * 30); + return true; + } + } + } + + return false; + } + private function isHospitalIntranet(string $ip): bool { if (in_array($ip, ['127.0.0.1', '::1', 'localhost'], true)) { @@ -300,6 +366,7 @@ class NursingApi extends BaseController if (session_status() === PHP_SESSION_ACTIVE || ! session_id()) { session()->set('pwa_auth_nurse_id', (int) $nurseRow['id']); } + service('cache')->save('api_device_token_' . $expectedDeviceToken, ['role' => 'nurse', 'id' => (int) $nurseRow['id']], 86400 * 30); return $this->response->setJSON([ 'status' => 1, diff --git a/app/Filters/ApiAuthFilter.php b/app/Filters/ApiAuthFilter.php new file mode 100644 index 0000000..ecb750b --- /dev/null +++ b/app/Filters/ApiAuthFilter.php @@ -0,0 +1,148 @@ +getMethod()) === 'OPTIONS') { + return null; + } + + $uriPath = trim((string) ($request->getUri()->getPath() ?? ''), '/'); + + // Check if path is explicitly exempt + foreach ($this->exemptPaths as $exempt) { + if ($uriPath === $exempt || str_ends_with($uriPath, $exempt)) { + return null; + } + } + + // 1. Check active user session (CodeIgniter Shield / HMS Admin) + if (function_exists('auth') && auth()->loggedIn()) { + return null; + } + + $session = session(); + if ($session->has('user_id') && (int) $session->get('user_id') > 0) { + return null; + } + + // 2. Check active PWA role-based sessions + if ($session->has('pwa_auth_nurse_id') && (int) $session->get('pwa_auth_nurse_id') > 0) { + return null; + } + + if ($session->has('pwa_auth_doctor_id') && (int) $session->get('pwa_auth_doctor_id') > 0) { + return null; + } + + if ($session->has('pwa_auth_store_id') && (int) $session->get('pwa_auth_store_id') > 0) { + return null; + } + + // 3. Check token from header or request parameters + $token = trim((string) $request->getHeaderLine('X-Device-Token')); + if ($token === '') { + $authHeader = trim((string) $request->getHeaderLine('Authorization')); + if (preg_match('/Bearer\s+([a-f0-9]{64})/i', $authHeader, $matches)) { + $token = $matches[1]; + } + } + + if ($token === '') { + $token = trim((string) ($request->getGet('device_token') ?? $request->getPost('device_token') ?? '')); + } + + if ($token !== '' && strlen($token) === 64) { + if ($this->validateDeviceToken($token)) { + return null; + } + } + + // Authentication failed - return 401 Unauthorized + return service('response') + ->setStatusCode(401) + ->setJSON([ + 'status' => 0, + 'error' => 'Unauthorized', + 'message' => 'Authentication required. Access to this endpoint requires an active session or valid authorization token.', + ]); + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + return $response; + } + + /** + * Validates device token against cache or database + */ + protected function validateDeviceToken(string $token): bool + { + $cache = service('cache'); + $cacheKey = 'api_device_token_' . $token; + + if ($cache->get($cacheKey)) { + return true; + } + + $db = \Config\Database::connect(); + + // Check against active nurses + $nurses = $db->table('nurse_master') + ->select('id, nurse_code, device_code') + ->where('is_active', 1) + ->where('device_code IS NOT NULL') + ->where('device_code !=', '') + ->get()->getResultArray(); + + foreach ($nurses as $nurse) { + $expected = hash_hmac('sha256', $nurse['id'] . '_' . ($nurse['nurse_code'] ?? ''), (string) $nurse['device_code']); + if (hash_equals($expected, $token)) { + $cache->save($cacheKey, ['role' => 'nurse', 'id' => (int) $nurse['id']], 86400 * 30); + return true; + } + } + + // Check against active doctors + $doctors = $db->table('doctor_master') + ->select('id, device_code') + ->where('active', 1) + ->where('device_code IS NOT NULL') + ->where('device_code !=', '') + ->get()->getResultArray(); + + foreach ($doctors as $doctor) { + $expected = hash_hmac('sha256', (string) $doctor['id'], (string) $doctor['device_code']); + if (hash_equals($expected, $token)) { + $cache->save($cacheKey, ['role' => 'doctor', 'id' => (int) $doctor['id']], 86400 * 30); + return true; + } + } + + return false; + } +} diff --git a/app/Filters/SecureHeadersFilter.php b/app/Filters/SecureHeadersFilter.php index df587f6..b2307c7 100644 --- a/app/Filters/SecureHeadersFilter.php +++ b/app/Filters/SecureHeadersFilter.php @@ -43,10 +43,12 @@ class SecureHeadersFilter implements FilterInterface // Cross-Origin isolation protections 'Cross-Origin-Opener-Policy' => 'same-origin-allow-popups', + 'Cross-Origin-Resource-Policy' => 'same-origin', + 'Cross-Origin-Embedder-Policy' => 'credentialless', // Content Security Policy (strict sources, trusted CDNs, preventing wildcards and injection) 'Content-Security-Policy' => "default-src 'self'; " . - "script-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: https://cdn.jsdelivr.net https://code.jquery.com https://cdn.datatables.net https://oss.maxcdn.com https://cdnjs.cloudflare.com; " . + "script-src 'self' 'unsafe-inline' data: blob: https://cdn.jsdelivr.net https://code.jquery.com https://cdn.datatables.net https://cdnjs.cloudflare.com; " . "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdn.datatables.net https://fonts.googleapis.com https://cdnjs.cloudflare.com; " . "font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com; " . "img-src 'self' data: blob: https://api.qrserver.com; " . @@ -68,13 +70,29 @@ class SecureHeadersFilter implements FilterInterface public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { + $uriPath = trim((string) ($request->getUri()->getPath() ?? ''), '/'); + $isApi = str_starts_with($uriPath, 'api/') || str_contains((string) $response->getHeaderLine('Content-Type'), 'application/json'); + foreach ($this->headers as $header => $value) { + // Apply strict sandbox CSP on API responses + if ($header === 'Content-Security-Policy' && $isApi) { + $response->setHeader('Content-Security-Policy', "default-src 'none'; frame-ancestors 'none'; sandbox;"); + continue; + } + // Only set if not already explicitly defined by a specific controller if (! $response->hasHeader($header)) { $response->setHeader($header, $value); } } + // Sensitive API endpoints must never be stored in browser/proxy caches + if ($isApi) { + $response->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0'); + $response->setHeader('Pragma', 'no-cache'); + $response->setHeader('Expires', '0'); + } + // Provide fresh CSRF token header for AJAX/fetch calls if (function_exists('csrf_hash')) { $response->setHeader('X-CSRF-TOKEN', csrf_hash()); diff --git a/app/Views/Invoice/Organization_invoice_print_v.php b/app/Views/Invoice/Organization_invoice_print_v.php index 0e55ac9..30ac878 100644 --- a/app/Views/Invoice/Organization_invoice_print_v.php +++ b/app/Views/Invoice/Organization_invoice_print_v.php @@ -19,12 +19,6 @@ - - -
diff --git a/app/Views/org_packing/create.php b/app/Views/org_packing/create.php index 8b434fe..8ef624e 100644 --- a/app/Views/org_packing/create.php +++ b/app/Views/org_packing/create.php @@ -2,7 +2,7 @@ Create New Packing - + ' + - '' + headerHtml + bodyHtml + ''); - printDoc.close(); - }; - - // 1. Daybook State - const todayStr = new Date().toISOString().split('T')[0]; - const [daybookFromDate, setDaybookFromDate] = useState(todayStr); - const [daybookToDate, setDaybookToDate] = useState(todayStr); - const [daybookData, setDaybookData] = useState(null); - const [loadingDaybook, setLoadingDaybook] = useState(false); - - // 2. Bank Audit State - const [bankAuditData, setBankAuditData] = useState(null); - const [auditFilterStatus, setAuditFilterStatus] = useState('all'); - const [auditSearch, setAuditSearch] = useState(''); - const [reconcilingSale, setReconcilingSale] = useState(null); - const [auditNotes, setAuditNotes] = useState(''); - const [auditorName, setAuditorName] = useState('Accountant'); - const [isSubmittingAudit, setIsSubmittingAudit] = useState(false); - - // 3. GST State - const currentMonthStr = todayStr.substring(0, 7); // YYYY-MM - const [gstMonth, setGstMonth] = useState(currentMonthStr); - const [gstData, setGstData] = useState(null); - const [loadingGst, setLoadingGst] = useState(false); - - // 4. Schedule H1 State - const [h1FromDate, setH1FromDate] = useState(todayStr); - const [h1ToDate, setH1ToDate] = useState(todayStr); - const [h1Search, setH1Search] = useState(''); - const [h1Records, setH1Records] = useState([]); - const [loadingH1, setLoadingH1] = useState(false); - - // 5. Staff & Customer Credit Accounts State - const [creditAccounts, setCreditAccounts] = useState([]); - const [loadingCredit, setLoadingCredit] = useState(false); - const [creditSearch, setCreditSearch] = useState(''); - const [showAddAccountModal, setShowAddAccountModal] = useState(false); - const [accFormType, setAccFormType] = useState('staff'); - const [accFormName, setAccFormName] = useState(''); - const [accFormPhone, setAccFormPhone] = useState(''); - const [accFormStaffId, setAccFormStaffId] = useState(''); - const [accFormDept, setAccFormDept] = useState(''); - const [accFormLimit, setAccFormLimit] = useState('5000'); - const [accFormRemarks, setAccFormRemarks] = useState(''); - const [isSavingAccount, setIsSavingAccount] = useState(false); - - // Credit Ledger Statement & Payment Settle Modal - const [selectedCreditAcc, setSelectedCreditAcc] = useState(null); - const [creditLedgerData, setCreditLedgerData] = useState(null); - const [loadingLedger, setLoadingLedger] = useState(false); - const [showPaymentModal, setShowPaymentModal] = useState(false); - const [payAmount, setPayAmount] = useState(''); - const [payMode, setPayMode] = useState('Cash'); - const [payRef, setPayRef] = useState(''); - const [payRemarks, setPayRemarks] = useState(''); - const [isRecordingPayment, setIsRecordingPayment] = useState(false); - - useEffect(() => { - if (!store?.store_id) return; - if (accTab === 'daybook') loadDaybook(daybookFromDate, daybookToDate); - if (accTab === 'bank_audit') loadBankAudit(auditFilterStatus, auditSearch); - if (accTab === 'gst') loadGst(gstMonth); - if (accTab === 'schedule_h1') loadScheduleH1(h1FromDate, h1ToDate, h1Search); - if (accTab === 'credit_accounts') loadCreditAccounts(); - }, [accTab, store?.store_id]); - - // DAYBOOK FUNCTIONS - const loadDaybook = async (from = daybookFromDate, to = daybookToDate) => { - setLoadingDaybook(true); - try { - const res = await fetch(`${API_BASE}accounting/daybook?store_id=${store.store_id}&from_date=${from}&to_date=${to}`); - const data = await res.json(); - if (data.status) setDaybookData(data); - } catch (e) { - console.error(e); - notify('Error loading daybook: ' + e.message, 'error'); - } finally { - setLoadingDaybook(false); - } - }; - - const handleDaybookFilterPreset = (preset) => { - const today = new Date(); - let from = todayStr; - let to = todayStr; - - if (preset === 'today') { - from = todayStr; - to = todayStr; - } else if (preset === 'yesterday') { - const y = new Date(today); - y.setDate(today.getDate() - 1); - from = y.toISOString().split('T')[0]; - to = from; - } else if (preset === 'last7') { - const w = new Date(today); - w.setDate(today.getDate() - 6); - from = w.toISOString().split('T')[0]; - to = todayStr; - } else if (preset === 'month') { - from = `${todayStr.substring(0, 7)}-01`; - to = todayStr; - } - setDaybookFromDate(from); - setDaybookToDate(to); - loadDaybook(from, to); - }; - - const exportDaybookCsv = () => { - if (!daybookData || !daybookData.transactions?.length) { - notify('No transactions to export for selected dates.', 'warning'); - return; - } - const headers = ['Invoice No', 'Sale Date', 'Patient Name', 'UHID', 'Doctor Name', 'Payment Mode', 'Subtotal (Rs)', 'Discount (Rs)', 'CGST (Rs)', 'SGST (Rs)', 'Net Amount (Rs)']; - const rows = daybookData.transactions.map(t => [ - t.invoice_no, - t.sale_date, - t.patient_name, - t.uhid || '', - t.doctor_name, - t.payment_mode, - t.subtotal, - t.discount_amount, - t.cgst_amount, - t.sgst_amount, - t.net_amount - ]); - downloadCsv(`Daybook_${daybookFromDate}_to_${daybookToDate}.csv`, [headers, ...rows]); - notify('Daybook CSV exported successfully.', 'success'); - }; - - const printDaybook = () => { - if (!daybookData || !daybookData.transactions?.length) { - notify('No transactions to print.', 'warning'); - return; - } - const s = daybookData.summary; - const html = ` -
-
Total Sales: ₹${Number(s.total_sales || 0).toLocaleString('en-IN')} (${s.total_invoices} bills)
-
Cash in Drawer: ₹${Number(s.cash_in_drawer || 0).toLocaleString('en-IN')}
-
UPI / QR: ₹${Number(s.upi_collection || 0).toLocaleString('en-IN')}
-
IPD / Staff Credit: ₹${Number(s.ipd_credit || 0).toLocaleString('en-IN')}
-
-

Period: ${daybookFromDate} to ${daybookToDate}

- - - - - - - - - - - - - - - ${daybookData.transactions.map(t => ` - - - - - - - - - - - `).join('')} - -
Invoice NoDate & TimePatient Name (UHID)DoctorModeCGST (₹)SGST (₹)Net Amount
${t.invoice_no}${t.sale_date}${t.patient_name} ${t.uhid ? '(' + t.uhid + ')' : ''}${t.doctor_name || 'N/A'}${t.payment_mode}₹${t.cgst_amount}₹${t.sgst_amount}₹${t.net_amount}
- `; - openPrintReport(`Daybook Journal (${daybookFromDate} to ${daybookToDate})`, html); - }; - - // BANK AUDIT FUNCTIONS - const loadBankAudit = async (status = auditFilterStatus, search = auditSearch) => { - try { - const params = new URLSearchParams({ - store_id: store.store_id, - status: status, - search: search - }); - const res = await fetch(`${API_BASE}accounting/bank-reconciliation?${params.toString()}`); - const data = await res.json(); - if (data.status) setBankAuditData(data); - } catch (e) { - console.error(e); - } - }; - - const handleReconcileSubmit = async (saleId, isReconciled) => { - setIsSubmittingAudit(true); - try { - const res = await fetch(API_BASE + 'accounting/reconcile-bank', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - sale_id: saleId, - is_reconciled: isReconciled ? 1 : 0, - reconciled_notes: auditNotes, - reconciled_by: auditorName - }) - }); - const data = await res.json(); - if (data.status) { - notify(data.message, 'success'); - setReconcilingSale(null); - setAuditNotes(''); - loadBankAudit(auditFilterStatus, auditSearch); - } else { - notify(data.message || 'Failed to update reconciliation', 'error'); - } - } catch (e) { - notify('Network error updating audit status: ' + e.message, 'error'); - } finally { - setIsSubmittingAudit(false); - } - }; - - const exportBankCsv = () => { - if (!bankAuditData || !bankAuditData.transactions?.length) { - notify('No bank/UPI transactions to export.', 'warning'); - return; - } - const headers = ['Invoice No', 'Sale Date', 'Patient', 'Mode', 'Amount (Rs)', 'UPI Ref No', 'Card Ref No', 'Audit Status', 'Reconciled By', 'Notes']; - const bankTxns = bankAuditData.transactions || bankAuditData.records || []; - const rows = bankTxns.map(t => [ - t.invoice_no, - t.sale_date, - t.patient_name, - t.payment_mode, - t.net_amount, - t.upi_ref_no || '', - t.card_ref_no || '', - t.is_reconciled == 1 ? 'RECONCILED' : 'PENDING', - t.reconciled_by || '', - t.reconciled_notes || '' - ]); - downloadCsv(`Bank_UPI_Reconciliation_${todayStr}.csv`, [headers, ...rows]); - notify('Bank & UPI Audit CSV exported.', 'success'); - }; - - const printBankAudit = () => { - if (!bankAuditData || !bankAuditData.transactions?.length) { - notify('No bank transactions to print.', 'warning'); - return; - } - const s = bankAuditData.summary || {}; - const html = ` -
-
Total UPI / Bank Sales: ₹${Number(s.total_amount || 0).toLocaleString('en-IN')} (${s.total_count} txns)
-
Verified / Reconciled: ₹${Number(s.reconciled_amount || 0).toLocaleString('en-IN')} (${s.reconciled_count})
-
Pending Verification: ₹${Number(s.pending_amount || 0).toLocaleString('en-IN')} (${s.pending_count})
-
- - - - - - - - - - - - - - - ${(bankAuditData.transactions || bankAuditData.records || []).map(t => ` - - - - - - - - - - - `).join('')} - -
Invoice NoDatePatient NameModeAmountUPI / UTR RefStatusAudited By
${t.invoice_no}${t.sale_date}${t.patient_name}${t.payment_mode}₹${t.net_amount}${t.upi_ref_no || t.card_ref_no || 'N/A'}${t.is_reconciled == 1 ? 'VERIFIED' : 'PENDING'}${t.reconciled_by || 'Unverified'}
- `; - openPrintReport('Bank & UPI Statement Audit Report', html); - }; - - // GST REPORT FUNCTIONS - const loadGst = async (m = gstMonth) => { - setLoadingGst(true); - try { - const res = await fetch(`${API_BASE}accounting/gst-report?store_id=${store.store_id}&month=${m}`); - const data = await res.json(); - if (data.status) setGstData(data); - } catch (e) { - console.error(e); - notify('Error loading GST report: ' + e.message, 'error'); - } finally { - setLoadingGst(false); - } - }; - - const exportGstCsv = () => { - if (!gstData || !gstData.gstr1_sales?.length) { - notify('No GST data to export for this month.', 'warning'); - return; - } - const headers = ['HSN Code', 'GST Slab (%)', 'Taxable Value (Rs)', 'CGST (Rs)', 'SGST (Rs)', 'IGST (Rs)', 'Total Value (Rs)']; - const rows = gstData.gstr1_sales.map(g => [ - g.hsn_code, - g.gst_rate, - Number(g.taxable_val).toFixed(2), - Number(g.cgst_val).toFixed(2), - Number(g.sgst_val).toFixed(2), - Number(g.igst_val).toFixed(2), - Number(g.total_val).toFixed(2) - ]); - downloadCsv(`GSTR1_Report_${gstMonth}.csv`, [headers, ...rows]); - notify('GSTR-1 CSV exported successfully.', 'success'); - }; - - // SCHEDULE H1 REGISTER FUNCTIONS - const loadScheduleH1 = async (from = h1FromDate, to = h1ToDate, search = h1Search) => { - setLoadingH1(true); - try { - const params = new URLSearchParams({ - store_id: store.store_id, - from_date: from, - to_date: to, - search: search - }); - const res = await fetch(`${API_BASE}compliance/schedule-h1-register?${params.toString()}`); - const data = await res.json(); - if (data.status) setH1Records(data.records || []); - } catch (e) { - console.error(e); - } finally { - setLoadingH1(false); - } - }; - - const exportH1Csv = () => { - if (!h1Records.length) { - notify('No Schedule H1 records to export.', 'warning'); - return; - } - const headers = ['Date', 'Bill No', 'Patient Name', 'Patient Address', 'Doctor Name', 'Doctor Reg No', 'Medicine Name', 'Batch No', 'Qty Supplied']; - const rows = h1Records.map(h => [ - h.sale_date, - h.invoice_no, - h.patient_name, - h.patient_address || '', - h.doctor_name, - h.doctor_reg_no || '', - h.item_name, - h.batch_no, - h.qty - ]); - downloadCsv(`Schedule_H1_Register_${h1FromDate}_to_${h1ToDate}.csv`, [headers, ...rows]); - notify('Schedule H1 Register CSV exported.', 'success'); - }; - - const printH1Register = () => { - if (!h1Records.length) { - notify('No Schedule H1 records to print.', 'warning'); - return; - } - const html = ` -
- Statutory Compliance: Mandatory Register under Drugs and Cosmetics (4th Amendment) Rules, 2013. Records must be retained for at least 3 years and open for inspection by Drug Inspector. -
-

Record Period: ${h1FromDate} to ${h1ToDate}

- - - - - - - - - - - - - - ${h1Records.map(h => ` - - - - - - - - - - `).join('')} - -
DateBill NoPatient Name & AddressPrescribing Doctor & Reg NoSchedule H1 Drug NameBatch NoQty Dispensed
${h.sale_date.split(' ')[0]}${h.invoice_no}${h.patient_name} ${h.patient_address ? '
' + h.patient_address + '' : ''}
${h.doctor_name} ${h.doctor_reg_no ? '
Reg: ' + h.doctor_reg_no + '' : ''}
${h.item_name}${h.batch_no}${h.qty}
- `; - openPrintReport('Statutory Schedule H1 Drug Register', html); - }; - - // CREDIT ACCOUNTS FUNCTIONS - const loadCreditAccounts = async () => { - setLoadingCredit(true); - try { - const res = await fetch(`${API_BASE}credit/accounts?store_id=${store.store_id}`); - const data = await res.json(); - if (data.status) setCreditAccounts(data.accounts || []); - } catch (e) { - console.error(e); - notify('Error loading credit accounts: ' + e.message, 'error'); - } finally { - setLoadingCredit(false); - } - }; - - const handleSaveCreditAccount = async (e) => { - e.preventDefault(); - if (!accFormName.trim()) { - notify('Account / Person Name is required', 'error'); - return; - } - setIsSavingAccount(true); - try { - const res = await fetch(`${API_BASE}credit/save-account`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - store_id: store.store_id, - account_type: accFormType, - account_name: accFormName.trim(), - phone: accFormPhone.trim(), - staff_id: accFormStaffId.trim(), - department: accFormDept.trim(), - credit_limit: Number(accFormLimit) || 0, - remarks: accFormRemarks.trim() - }) - }); - const data = await res.json(); - if (data.status) { - notify('Credit account created successfully.', 'success'); - setShowAddAccountModal(false); - setAccFormName(''); - setAccFormPhone(''); - setAccFormStaffId(''); - setAccFormDept(''); - setAccFormRemarks(''); - loadCreditAccounts(); - } else { - notify(data.message || 'Failed to create credit account', 'error'); - } - } catch (err) { - notify('Error: ' + err.message, 'error'); - } finally { - setIsSavingAccount(false); - } - }; - - const openAccountLedger = async (acc) => { - setSelectedCreditAcc(acc); - setLoadingLedger(true); - try { - const res = await fetch(`${API_BASE}credit/ledger/${acc.account_id}?store_id=${store.store_id}`); - const data = await res.json(); - if (data.status) { - setCreditLedgerData(data); - } - } catch (e) { - notify('Error loading account ledger: ' + e.message, 'error'); - } finally { - setLoadingLedger(false); - } - }; - - const openSettlePaymentModal = (acc) => { - setSelectedCreditAcc(acc); - setPayAmount(acc.current_balance > 0 ? String(acc.current_balance) : ''); - setPayMode('Cash'); - setPayRef(''); - setPayRemarks(''); - setShowPaymentModal(true); - }; - - const handleRecordPayment = async (e) => { - e.preventDefault(); - const amt = Number(payAmount); - if (!amt || amt <= 0) { - notify('Please enter a valid payment amount.', 'error'); - return; - } - setIsRecordingPayment(true); - try { - const res = await fetch(`${API_BASE}credit/record-payment`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - store_id: store.store_id, - account_id: selectedCreditAcc.account_id, - amount: amt, - payment_mode: payMode, - payment_ref: payRef.trim(), - remarks: payRemarks.trim(), - recorded_by_name: 'Accountant' - }) - }); - const data = await res.json(); - if (data.status) { - notify(`Settlement of ₹${amt} recorded successfully. New balance: ₹${data.new_balance}`, 'success'); - setShowPaymentModal(false); - loadCreditAccounts(); - if (selectedCreditAcc) { - openAccountLedger({ ...selectedCreditAcc, current_balance: data.new_balance }); - } - } else { - notify(data.message || 'Failed to record payment', 'error'); - } - } catch (err) { - notify('Error recording payment: ' + err.message, 'error'); - } finally { - setIsRecordingPayment(false); - } - }; - - const printAccountLedger = () => { - if (!creditLedgerData || !selectedCreditAcc) return; - const html = ` -
-
-
- Account Name: ${selectedCreditAcc.account_name} (${selectedCreditAcc.account_type.toUpperCase()})
- Phone: ${selectedCreditAcc.phone || 'N/A'}
- Dept / Staff ID: ${selectedCreditAcc.department || ''} ${selectedCreditAcc.staff_id ? '(' + selectedCreditAcc.staff_id + ')' : ''} -
-
- Credit Limit: ₹${Number(selectedCreditAcc.credit_limit || 0).toLocaleString('en-IN')}
- Current Outstanding: ₹${Number(selectedCreditAcc.current_balance || 0).toLocaleString('en-IN')} -
-
-
- - - - - - - - - - - - - - ${creditLedgerData.entries.map(e => ` - - - - - - - - - - `).join('')} - -
DateTypeInvoice / Ref NoDebit (Bills)Credit (Payments)Balance AfterRecorded By / Remarks
${e.created_at}${e.entry_type === 'DEBIT' ? 'BILL DEBIT' : 'PAYMENT'}${e.invoice_no || e.payment_ref || '-'}${Number(e.debit_amount) > 0 ? '₹' + Number(e.debit_amount).toFixed(2) : '-'}${Number(e.credit_amount) > 0 ? '₹' + Number(e.credit_amount).toFixed(2) : '-'}₹${Number(e.balance_after).toFixed(2)}${e.remarks || ''} (${e.recorded_by_name || 'Staff'})
- `; - openPrintReport(`Credit Account Statement - ${selectedCreditAcc.account_name}`, html); - }; - - // Filtered credit accounts - const filteredCreditAccounts = creditAccounts.filter(acc => { - if (!creditSearch) return true; - const q = creditSearch.toLowerCase(); - return (acc.account_name && acc.account_name.toLowerCase().includes(q)) || - (acc.phone && acc.phone.includes(q)) || - (acc.staff_id && acc.staff_id.toLowerCase().includes(q)) || - (acc.department && acc.department.toLowerCase().includes(q)); - }); - - const totalOutstandingCredit = creditAccounts.reduce((sum, a) => sum + Number(a.current_balance || 0), 0); - - return ( -
- {/* Top Navigation Tabs */} -
- - - - - -
- - {/* TAB 1: DAYBOOK */} - {accTab === 'daybook' && ( -
- {/* Daybook Filter Toolbar */} -
-
-
- Quick Filter: - - - - -
- -
-
- - setDaybookFromDate(e.target.value)} - /> -
-
- - setDaybookToDate(e.target.value)} - /> -
- -
- - -
-
-
-
- - {daybookData && ( -
-
-
-
- TOTAL PERIOD SALES -

₹{Number(daybookData.summary.total_sales || 0).toLocaleString('en-IN')}

- {daybookData.summary.total_invoices} Bills -
-
-
-
- CASH IN DRAWER -

₹{Number(daybookData.summary.cash_in_drawer || 0).toLocaleString('en-IN')}

-
-
-
-
- UPI / QR COLLECTIONS -

₹{Number(daybookData.summary.upi_collection || 0).toLocaleString('en-IN')}

-
-
-
-
- CREDIT BILLED (IPD + STAFF) -

₹{Number(daybookData.summary.ipd_credit || 0).toLocaleString('en-IN')}

-
-
-
- -
-
-
Transactions Journal ({daybookFromDate} to {daybookToDate})
- {daybookData.transactions.length} Records -
-
- - - - - - - - - - - - - - - {daybookData.transactions.length === 0 ? ( - - - - ) : ( - daybookData.transactions.map((t) => ( - - - - - - - - - - - )) - )} - -
Invoice NoDate & TimePatient (UHID)DoctorModeCGST (₹)SGST (₹)Net Amount
No transactions found for the selected date range.
{t.invoice_no}{t.sale_date}{t.patient_name} {t.uhid ? `(${t.uhid})` : ''}{t.doctor_name}{t.payment_mode}₹{t.cgst_amount}₹{t.sgst_amount}₹{t.net_amount}
-
-
-
- )} -
- )} - - {/* TAB 2: BANK AUDIT */} - {accTab === 'bank_audit' && ( -
-
-
-
- TOTAL ONLINE / UPI SALES -

₹{Number(bankAuditData?.summary?.total_amount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2 })}

- {bankAuditData?.summary?.total_count || 0} Transactions Recorded -
-
-
-
- STATEMENT RECONCILED (VERIFIED) -

₹{Number(bankAuditData?.summary?.reconciled_amount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2 })}

- {bankAuditData?.summary?.reconciled_count || 0} Bills Matched with Bank -
-
-
-
- PENDING AUDIT VERIFICATION -

₹{Number(bankAuditData?.summary?.pending_amount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2 })}

- {bankAuditData?.summary?.pending_count || 0} Bills Unverified -
-
-
- -
-
-
-
- - - -
-
- -
-
- - { - setAuditSearch(e.target.value); - loadBankAudit(auditFilterStatus, e.target.value); - }} - /> -
-
- -
- - -
-
-
- -
-
- - - - - - - - - - - - - - - {(() => { - const txns = bankAuditData?.transactions || bankAuditData?.records || []; - if (!bankAuditData) { - return ; - } - if (txns.length === 0) { - return ; - } - return txns.map((t) => ( - - - - - - - - - - - )); - })()} - -
Invoice NoDate & TimePatientModeBill TotalBank / UTR ReferenceAudit StatusAction
Loading bank audit records...
No transactions found matching the filter.
{t.invoice_no}{t.sale_date}{t.patient_name}{t.payment_mode}₹{t.net_amount} - {t.upi_ref_no ? ( -
UPI {t.upi_ref_no}
- ) : t.card_ref_no ? ( -
CARD {t.card_ref_no}
- ) : ( - Direct QR - )} -
- {t.is_reconciled == 1 ? ( -
- Reconciled -
{t.reconciled_by} • {t.reconciled_at?.split(' ')[0]}
-
- ) : ( - Pending Statement - )} -
- {t.is_reconciled == 1 ? ( - - ) : ( - - )} -
-
-
- - {/* Reconcile Modal */} - {reconcilingSale && ( -
-
-
-
-
- Reconcile Bank / UPI Statement -
- -
-
-
-
- Invoice No: - {reconcilingSale.invoice_no} -
-
- Amount: - ₹{reconcilingSale.net_amount} -
-
- Recorded Ref / UTR: - {reconcilingSale.upi_ref_no || reconcilingSale.card_ref_no || 'Direct Store QR'} -
-
- -
- - setAuditorName(e.target.value)} - /> -
- -
- - -
-
-
- - -
-
-
-
- )} -
- )} - - {/* TAB 3: GST RETURNS */} - {accTab === 'gst' && ( -
-
-
-
- - { - setGstMonth(e.target.value); - loadGst(e.target.value); - }} - /> - -
-
- -
-
-
- - {gstData && ( -
-
-
GSTR-1 Outward Sales Summary (HSN-wise) for {gstMonth}
- GSTIN: {store.gst_no || 'N/A'} -
-
- - - - - - - - - - - - - - {gstData.gstr1_sales.length === 0 ? ( - - - - ) : ( - gstData.gstr1_sales.map((g, i) => ( - - - - - - - - - - )) - )} - -
HSN CodeGST SlabTaxable Value (₹)CGST (₹)SGST (₹)IGST (₹)Total Invoice Value (₹)
No sales recorded for GST filing in month {gstMonth}.
{g.hsn_code}{g.gst_rate}%₹{Number(g.taxable_val).toFixed(2)}₹{Number(g.cgst_val).toFixed(2)}₹{Number(g.sgst_val).toFixed(2)}₹{Number(g.igst_val).toFixed(2)}₹{Number(g.total_val).toFixed(2)}
-
-
- )} -
- )} - - {/* TAB 4: SCHEDULE H1 DRUG REGISTER */} - {accTab === 'schedule_h1' && ( -
-
-
-
- Date Filter: -
- setH1FromDate(e.target.value)} - /> - to - setH1ToDate(e.target.value)} - /> -
- -
- -
- { - setH1Search(e.target.value); - loadScheduleH1(h1FromDate, h1ToDate, e.target.value); - }} - /> - - -
-
-
- -
-
-
-
Statutory Schedule H1 Drug Register
- Mandatory under Indian Drugs & Cosmetics Rules (4th Amendment 2013). Retain for 3 years. -
- {h1Records.length} Dispensed Entries -
- -
- - - - - - - - - - - - - - {h1Records.length === 0 ? ( - - - - ) : ( - h1Records.map((h, i) => ( - - - - - - - - - - )) - )} - -
DateBill NoPatient Name & AddressPrescribing Doctor & Reg NoMedicine NameBatch NoQty Supplied
No Schedule H1 medicines dispensed in this period.
{h.sale_date?.split(' ')[0]}{h.invoice_no}{h.patient_name} {h.patient_address ? `(${h.patient_address})` : ''}{h.doctor_name} {h.doctor_reg_no ? `(Reg: ${h.doctor_reg_no})` : ''}{h.item_name}{h.batch_no}{h.qty}
-
-
-
- )} - - {/* TAB 5: STAFF & CUSTOMER CREDIT ACCOUNTS */} - {accTab === 'credit_accounts' && ( -
- {/* KPI Cards */} -
-
-
- TOTAL REGISTERED ACCOUNTS -

{creditAccounts.length} Accounts

- Staff, Doctors, Institutional & Patients -
-
-
-
- TOTAL OUTSTANDING DUES -

₹{totalOutstandingCredit.toLocaleString('en-IN', { minimumFractionDigits: 2 })}

- Unsettled Pharmacy Debits -
-
-
-
- TOTAL CREDIT LIMIT SANCTIONED -

- ₹{creditAccounts.reduce((sum, a) => sum + Number(a.credit_limit || 0), 0).toLocaleString('en-IN', { minimumFractionDigits: 2 })} -

- Authorized Spending Cap -
-
-
- - {/* Toolbar */} -
-
-
-
- - setCreditSearch(e.target.value)} - /> -
-
-
- -
-
-
- - {/* Accounts Table */} -
-
- - - - - - - - - - - - - - - {loadingCredit ? ( - - ) : filteredCreditAccounts.length === 0 ? ( - - ) : ( - filteredCreditAccounts.map(acc => { - const typeColor = - acc.account_type === 'staff' ? 'primary' : - acc.account_type === 'doctor' ? 'success' : - acc.account_type === 'corporate' ? 'dark' : 'warning'; - const bal = Number(acc.current_balance || 0); - - return ( - - - - - - - - - - - ); - }) - )} - -
Account / Person NameAccount TypeDept / Staff IDPhoneCredit LimitCurrent BalanceStatusActions
Loading credit accounts...
No credit accounts found. Click "New Credit Account" to create one.
- {acc.account_name} - {acc.remarks && {acc.remarks}} - - - {acc.account_type} - - {acc.department || acc.staff_id || '-'}{acc.phone || '-'}₹{Number(acc.credit_limit || 0).toLocaleString('en-IN')} - 0 ? 'text-danger' : 'text-success'}`}> - ₹{bal.toLocaleString('en-IN', { minimumFractionDigits: 2 })} - - - - {acc.is_active == 1 ? 'ACTIVE' : 'INACTIVE'} - - -
- - -
-
-
-
- - {/* Modal: New Credit Account */} - {showAddAccountModal && ( -
-
-
-
-
-
- Create Credit Account -
- -
-
-
-
- - -
-
- - setAccFormLimit(e.target.value)} - placeholder="5000" - /> -
-
- -
- - setAccFormName(e.target.value)} - placeholder="e.g. Dr. Rajesh Sharma / Sister Sunita" - /> -
- -
-
- - setAccFormPhone(e.target.value)} - placeholder="e.g. 9876543210" - /> -
-
- - setAccFormStaffId(e.target.value)} - placeholder="e.g. EMP-1042" - /> -
-
- -
- - setAccFormDept(e.target.value)} - placeholder="e.g. ICU Nursing / General Surgery / Administration" - /> -
- -
- - -
-
-
- - -
-
-
-
-
- )} - - {/* Modal: View Account Ledger */} - {selectedCreditAcc && creditLedgerData && ( -
-
-
-
-
- -
-
{selectedCreditAcc.account_name} — Credit Statement
- {selectedCreditAcc.account_type.toUpperCase()} • {selectedCreditAcc.department || 'General'} -
-
- -
- -
- {/* Statement Summary Card */} -
-
-
- CREDIT LIMIT -
₹{Number(selectedCreditAcc.credit_limit || 0).toLocaleString('en-IN')}
-
-
- OUTSTANDING BALANCE -

₹{Number(selectedCreditAcc.current_balance || 0).toLocaleString('en-IN', { minimumFractionDigits: 2 })}

-
-
- AVAILABLE CREDIT -
- ₹{Math.max(0, Number(selectedCreditAcc.credit_limit || 0) - Number(selectedCreditAcc.current_balance || 0)).toLocaleString('en-IN')} -
-
-
- - -
-
-
- - {/* Ledger Entries Table */} -
- - - - - - - - - - - - - - - {creditLedgerData.entries.length === 0 ? ( - - ) : ( - creditLedgerData.entries.map(ent => ( - - - - - - - - - - - )) - )} - -
TimestampTypeInvoice / Receipt RefDebit (Bills)Credit (Payments)Running BalanceModeRecorded By / Notes
No transactions on this account yet.
{ent.created_at} - - {ent.entry_type} - - {ent.invoice_no || ent.payment_ref || '-'} - {Number(ent.debit_amount) > 0 ? '₹' + Number(ent.debit_amount).toFixed(2) : '-'} - - {Number(ent.credit_amount) > 0 ? '₹' + Number(ent.credit_amount).toFixed(2) : '-'} - - ₹{Number(ent.balance_after).toFixed(2)} - {ent.payment_mode} - {ent.remarks || 'Bill Charge'} ({ent.recorded_by_name || 'System'}) -
-
-
-
- -
-
-
-
- )} - - {/* Modal: Record Payment Settlement */} - {showPaymentModal && selectedCreditAcc && ( -
-
-
-
-
-
- Record Credit Settlement Payment -
- -
-
-
-
- Account: - {selectedCreditAcc.account_name} -
-
- Total Outstanding Due: - ₹{Number(selectedCreditAcc.current_balance || 0).toFixed(2)} -
-
- -
- -
- ₹ - setPayAmount(e.target.value)} - placeholder="Enter amount" - /> - -
-
- -
-
- - -
-
- - setPayRef(e.target.value)} - placeholder="e.g. UTR-991823" - /> -
-
- -
- - -
-
-
- - -
-
-
-
-
- )} -
- )} -
- ); -} - -function StaffManagementView({ store, notify, activeOperator, onOperatorUpdated, onSelectOperator }) { - if (!store) return null; - const [staffList, setStaffList] = useState([]); - const [loading, setLoading] = useState(false); - - // Modal state for Add/Edit Staff - const [showEditModal, setShowEditModal] = useState(false); - const [editingUser, setEditingUser] = useState(null); - const [formFullName, setFormFullName] = useState(''); - const [formUsername, setFormUsername] = useState(''); - const [formPinCode, setFormPinCode] = useState(''); - const [formRole, setFormRole] = useState('pharmacist'); - const [formPhone, setFormPhone] = useState(''); - const [formRegNo, setFormRegNo] = useState(''); - const [formHprId, setFormHprId] = useState(''); - const [formIsDefault, setFormIsDefault] = useState(false); - const [formIsActive, setFormIsActive] = useState(true); - const [isSaving, setIsSaving] = useState(false); - - // 6 Granular Permissions Matrix - const defaultPermissions = { - admin: false, - sale: true, - purchase: false, - sale_edit_after_1h: false, - purchase_edit_verified: false, - bank_upi_audit: false - }; - const [formPermissions, setFormPermissions] = useState(defaultPermissions); - - const applyRoleDefaults = (role) => { - setFormRole(role); - if (role === 'store_manager') { - setFormPermissions({ - admin: true, - sale: true, - purchase: true, - sale_edit_after_1h: true, - purchase_edit_verified: true, - bank_upi_audit: true - }); - } else if (role === 'pharmacist') { - setFormPermissions({ - admin: false, - sale: true, - purchase: true, - sale_edit_after_1h: false, - purchase_edit_verified: false, - bank_upi_audit: false - }); - } else if (role === 'cashier') { - setFormPermissions({ - admin: false, - sale: true, - purchase: false, - sale_edit_after_1h: false, - purchase_edit_verified: false, - bank_upi_audit: false - }); - } else if (role === 'auditor') { - setFormPermissions({ - admin: false, - sale: false, - purchase: false, - sale_edit_after_1h: false, - purchase_edit_verified: false, - bank_upi_audit: true - }); - } - }; - - useEffect(() => { - if (store?.store_id) { - loadStaff(); - } - }, [store?.store_id]); - - const loadStaff = async () => { - setLoading(true); - try { - const res = await fetch(`${API_BASE}users?store_id=${store.store_id}`); - const data = await res.json(); - if (data.status) { - setStaffList(data.users || []); - } - } catch (e) { - console.error("Failed to load staff:", e); - } finally { - setLoading(false); - } - }; - - const openAddModal = () => { - setEditingUser(null); - setFormFullName(''); - setFormUsername(''); - setFormPinCode('1234'); - applyRoleDefaults('pharmacist'); - setFormPhone(''); - setFormRegNo(''); - setFormHprId(''); - setFormIsDefault(false); - setFormIsActive(true); - setShowEditModal(true); - }; - - const openEditModal = (user) => { - setEditingUser(user); - setFormFullName(user.full_name || ''); - setFormUsername(user.username || ''); - setFormPinCode(''); // Keep empty unless resetting - setFormRole(user.user_role || 'pharmacist'); - setFormPhone(user.phone || ''); - setFormRegNo(user.pharmacist_reg_no || ''); - setFormHprId(user.pharmacist_hpr_id || ''); - setFormIsDefault(user.is_default == 1); - setFormIsActive(user.is_active == 1); - - // Parse permissions - let perms = { ...defaultPermissions }; - if (user.permissions) { - try { - const parsed = typeof user.permissions === 'string' ? JSON.parse(user.permissions) : user.permissions; - perms = { ...defaultPermissions, ...parsed }; - } catch (e) { - console.warn('Error parsing user permissions:', e); - } - } - setFormPermissions(perms); - setShowEditModal(true); - }; - - const togglePermission = (key) => { - setFormPermissions(prev => ({ - ...prev, - [key]: !prev[key] - })); - }; - - const handleSaveStaff = async (e) => { - e.preventDefault(); - if (!formFullName.trim() || !formUsername.trim()) { - notify('Full Name and Username are required.', 'error'); - return; - } - - setIsSaving(true); - try { - const payload = { - user_id: editingUser ? editingUser.user_id : 0, - store_id: store.store_id, - full_name: formFullName.trim(), - username: formUsername.trim(), - user_role: formRole, - phone: formPhone.trim(), - pharmacist_reg_no: formRegNo.trim(), - pharmacist_hpr_id: formHprId.trim(), - is_default: formIsDefault ? 1 : 0, - is_active: formIsActive ? 1 : 0, - permissions: JSON.stringify(formPermissions) - }; - if (formPinCode.trim()) { - payload.pin_code = formPinCode.trim(); - } - - const res = await fetch(`${API_BASE}users/save`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) - }); - const data = await res.json(); - if (data.status) { - notify('Staff profile and permission matrix saved successfully.', 'success'); - setShowEditModal(false); - loadStaff(); - if (onOperatorUpdated) onOperatorUpdated(); - } else { - notify(data.message || 'Failed to save staff profile.', 'error'); - } - } catch (err) { - notify('Network error saving staff profile.', 'error'); - } finally { - setIsSaving(false); - } - }; - - return ( -
- {/* Header & Add Button */} -
-
-
- Medical Store Staff & 6-Tier Permission Matrix -
-

- Manage pharmacy staff credentials, cashier PINs, and granular audit/sale/purchase rights for {store.store_name} -

-
-
- -
-
- - {/* Staff Cards Grid */} -
- {loading ? ( -
- Loading staff profiles... -
- ) : staffList.length === 0 ? ( -
- - No staff members assigned to this store yet. Click "Add Staff Member" to get started. -
- ) : ( - staffList.map((user) => { - const isCurrent = activeOperator?.user_id == user.user_id; - const roleColor = - user.user_role === 'store_manager' ? 'primary' : - user.user_role === 'pharmacist' ? 'success' : - user.user_role === 'auditor' ? 'info' : - user.user_role === 'cashier' ? 'warning' : 'secondary'; - - let perms = {}; - try { - perms = typeof user.permissions === 'string' ? JSON.parse(user.permissions || '{}') : (user.permissions || {}); - } catch (e) { - perms = {}; - } - - return ( -
-
-
-
-
- {user.full_name ? user.full_name[0] : 'U'} -
-
-
{user.full_name}
- @{user.username} -
-
- - {user.user_role ? user.user_role.replace(/_/g, ' ') : 'STAFF'} - -
- -
-
{user.phone || 'No phone set'}
- {user.pharmacist_reg_no ? ( -
- Reg: {user.pharmacist_reg_no} -
- ) : null} -
- - {/* Granular Permission Tags */} -
-
Assigned Rights
-
- - Admin - - - Sale - - - Purchase - - - Sale Edit >1h - - - Purch Edit Verif - - - Bank Audit - -
-
- -
-
- {isCurrent ? ( - - Active Cashier - - ) : ( - - )} -
- -
-
-
- ); - }) - )} -
- - {/* Add / Edit Staff Modal */} - {showEditModal && ( -
-
-
-
-
-
- - {editingUser ? 'Edit Staff Profile & Permissions' : 'Register New Staff Member'} -
- -
-
-
-
- - setFormFullName(e.target.value)} - placeholder="e.g. Rahul Sharma" - /> -
-
- - setFormUsername(e.target.value)} - placeholder="e.g. rahul_pharma" - /> -
-
- -
-
- - -
-
- - setFormPinCode(e.target.value)} - placeholder={editingUser ? 'Leave blank to keep current PIN' : 'e.g. 1234'} - /> -
-
- - setFormPhone(e.target.value)} - placeholder="e.g. 9876543210" - /> -
-
- -
-
- - setFormRegNo(e.target.value)} - placeholder="e.g. PB-PH-99214" - /> -
-
- - setFormHprId(e.target.value)} - placeholder="e.g. rahul@hpr.abdm" - /> -
-
- - {/* 6-Tier Permission Matrix Checklist */} -
-
- Granular Access & Audit Permissions - Audit Compliant -
-
-
-
- togglePermission('admin')} - /> - -
Store config & user management
-
-
-
-
- togglePermission('sale')} - /> - -
Counter POS and draft billing
-
-
-
-
- togglePermission('purchase')} - /> - -
Challans & stock additions
-
-
-
-
- togglePermission('sale_edit_after_1h')} - /> - -
Modify bills older than 60 mins
-
-
-
-
- togglePermission('purchase_edit_verified')} - /> - -
Edit purchase after verification
-
-
-
-
- togglePermission('bank_upi_audit')} - /> - -
Verify statements & reconciliations
-
-
-
-
- -
-
- setFormIsDefault(e.target.checked)} - /> - -
-
- setFormIsActive(e.target.checked)} - /> - -
-
-
-
- - -
-
-
-
-
- )} -
- ); -} - -// Note: Store & Statutory Licensing Setup is managed centrally in HMS -> Admin -> Medical Store. - -// ========================================================================= -// 8. STAFF & OPERATOR ROLE MANAGEMENT (END) -// ========================================================================= - -function MobileAppView({ store, stores, notify, activeOperator, onSwitchOperator, onExitMobile, triggerPwaInstall }) { - if (!store) return null; - const [mobTab, setMobTab] = useState('dashboard'); // 'dashboard', 'collector', 'auditor', 'purchase_photo' - - // Dashboard Data - const [dashData, setDashData] = useState(null); - const [loadingDash, setLoadingDash] = useState(false); - - // Rack Collector (Draft Bill) State - const [collectorItems, setCollectorItems] = useState([]); - const [itemSearchQuery, setItemSearchQuery] = useState(''); - const [searchResults, setSearchResults] = useState([]); - const [selectedItem, setSelectedItem] = useState(null); - const [selectedBatch, setSelectedBatch] = useState(null); - const [collectQty, setCollectQty] = useState(1); - const [collectUnit, setCollectUnit] = useState('Tablet'); - const [patientName, setPatientName] = useState(''); - const [patientMobile, setPatientMobile] = useState(''); - const [bedNo, setBedNo] = useState(''); - const [wardName, setWardName] = useState(''); - const [doctorName, setDoctorName] = useState(''); - const [isSavingDraft, setIsSavingDraft] = useState(false); - - // Stock Auditor State - const [auditSearch, setAuditSearch] = useState(''); - const [auditResults, setAuditResults] = useState([]); - const [auditModalItem, setAuditModalItem] = useState(null); - const [auditCount, setAuditCount] = useState(''); - const [auditReason, setAuditReason] = useState('PHYSICAL_VARIATION'); - const [auditRemarks, setAuditRemarks] = useState(''); - const [isSubmittingAudit, setIsSubmittingAudit] = useState(false); - - // Purchase Invoice Camera State - const [recentPurchases, setRecentPurchases] = useState([]); - const [selectedPurchaseId, setSelectedPurchaseId] = useState(''); - const [capturedImageBase64, setCapturedImageBase64] = useState(null); - const [isUploadingPhoto, setIsUploadingPhoto] = useState(false); - const [previewPhotoUrl, setPreviewPhotoUrl] = useState(null); - - useEffect(() => { - if (store?.store_id) { - loadDashboard(); - loadRecentPurchases(); - } - }, [store?.store_id]); - - const loadDashboard = async () => { - setLoadingDash(true); - try { - const res = await fetch(API_BASE + `mobile/dashboard?store_id=${store.store_id}`); - const data = await res.json(); - if (data.status) setDashData(data); - } catch(e) { - console.error("Failed to load mobile dashboard:", e); - } finally { - setLoadingDash(false); - } - }; - - const loadRecentPurchases = async () => { - try { - const res = await fetch(API_BASE + `purchases?store_id=${store.store_id}&limit=15`); - const data = await res.json(); - if (data.status) { - setRecentPurchases(data.purchases || []); - if (data.purchases && data.purchases.length > 0) { - setSelectedPurchaseId(data.purchases[0].purchase_id); - } - } - } catch(e) { - console.error("Failed to load purchases:", e); - } - }; - - // Medicine Search for Collector - const handleSearchItems = async (q) => { - setItemSearchQuery(q); - if (q.trim().length < 2) { - setSearchResults([]); - return; - } - try { - const res = await fetch(API_BASE + `items/search?store_id=${store.store_id}&q=${encodeURIComponent(q.trim())}`); - const data = await res.json(); - if (data.status) { - setSearchResults(data.items || []); - } - } catch(e) { - console.error(e); - } - }; - - const addItemToDraft = () => { - if (!selectedItem || !selectedBatch) { - notify('Please select medicine item and batch.', 'error'); - return; - } - const q = Number(collectQty); - if (q <= 0) { - notify('Quantity must be greater than 0.', 'error'); - return; - } - - const upp = Number(selectedItem.units_per_pack || selectedBatch.units_per_pack || 1); - const stripMrp = Number(selectedBatch.mrp || 0); - const perUnitMrp = upp > 0 ? (stripMrp / upp) : stripMrp; - const totalUnits = collectUnit === 'Strip' ? (q * upp) : q; - const rate = collectUnit === 'Strip' ? stripMrp : perUnitMrp; - const lineGross = collectUnit === 'Strip' ? (q * stripMrp) : (q * perUnitMrp); - - const newItem = { - item_id: selectedItem.item_id, - item_name: selectedItem.item_name, - generic_name: selectedItem.generic_name || '', - unit_pack: selectedItem.unit_pack || (upp > 1 ? `Pack: ${upp} Tabs` : 'Unit'), - units_per_pack: upp, - drug_schedule: selectedItem.drug_schedule || '', - hsn_code: selectedItem.hsn_code || '3004', - gst_rate: Number(selectedBatch.gst_rate ?? selectedItem.gst_rate ?? 12.0), - batch_id: selectedBatch.batch_id, - batch_no: selectedBatch.batch_no, - expiry_display: selectedBatch.expiry_display || (selectedBatch.expiry_date ? selectedBatch.expiry_date.substring(0, 7) : ''), - expiry_date: selectedBatch.expiry_date, - current_qty: selectedBatch.current_qty || 0, - unit_mrp: stripMrp, - mrp: stripMrp, - qty: q, - sell_unit: collectUnit, - strip_qty: collectUnit === 'Strip' ? q : 0, - loose_qty: (collectUnit === 'Tablet' || collectUnit === 'Unit') ? q : 0, - total_units: totalUnits, - effective_rate: Number(rate.toFixed(2)), - line_gross: Number(lineGross.toFixed(2)) - }; - - setCollectorItems(prev => [...prev, newItem]); - setSelectedItem(null); - setSelectedBatch(null); - setItemSearchQuery(''); - setSearchResults([]); - setCollectQty(1); - notify(`Added ${newItem.item_name} (${newItem.qty} ${collectUnit}) to draft basket`, 'success'); - }; - - const handleSaveDraft = async () => { - if (collectorItems.length === 0) { - notify('Draft basket is empty! Add items from shelves.', 'error'); - return; - } - - setIsSavingDraft(true); - try { - const res = await fetch(API_BASE + 'drafts/save', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - store_id: store.store_id, - patient_name: patientName.trim() || 'Walk-in Customer', - patient_mobile: patientMobile.trim(), - bed_no: bedNo.trim(), - ward_name: wardName.trim(), - doctor_name: doctorName.trim(), - collected_by_name: activeOperator ? activeOperator.full_name : 'Mobile Pharmacist', - items: collectorItems - }) - }); - const data = await res.json(); - if (data.status) { - notify(`✓ Draft Bill #${data.draft_code} saved! Cashier on counter PC can now bill it.`, 'success'); - setCollectorItems([]); - setPatientName(''); - setPatientMobile(''); - setBedNo(''); - setWardName(''); - setDoctorName(''); - } else { - notify(data.message || 'Failed to save draft bill.', 'error'); - } - } catch(e) { - notify('Network error saving draft bill: ' + e.message, 'error'); - } finally { - setIsSavingDraft(false); - } - }; - - // Auditor Search - const handleSearchAudit = async (q) => { - setAuditSearch(q); - if (q.trim().length < 2) { - setAuditResults([]); - return; - } - try { - const res = await fetch(API_BASE + `stock/list?store_id=${store.store_id}&limit=20&filter=all`); - const data = await res.json(); - if (data.status && data.stock) { - const filtered = data.stock.filter(s => - s.item_name.toLowerCase().includes(q.toLowerCase()) || - (s.generic_name && s.generic_name.toLowerCase().includes(q.toLowerCase())) || - s.batch_no.toLowerCase().includes(q.toLowerCase()) || - (s.shelf_no && s.shelf_no.toLowerCase().includes(q.toLowerCase())) - ); - setAuditResults(filtered); - } - } catch(e) { - console.error(e); - } - }; - - const handleMobileReconcile = async () => { - if (!auditModalItem) return; - const pQty = Number(auditCount); - if (isNaN(pQty) || pQty < 0) { - notify('Please enter valid physical count (>=0).', 'error'); - return; - } - - setIsSubmittingAudit(true); - try { - const res = await fetch(API_BASE + 'stock/reconcile', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - store_id: store.store_id, - item_id: auditModalItem.item_id, - batch_id: auditModalItem.batch_id, - physical_qty: pQty, - audit_type: auditReason, - remarks: auditRemarks.trim() || `Mobile Shelf Audit by ${activeOperator?.full_name || 'Staff'}`, - operator_id: activeOperator?.user_id || 1, - operator_name: activeOperator?.full_name || 'Mobile Auditor' - }) - }); - const data = await res.json(); - if (data.status) { - notify(`Reconciled ${auditModalItem.item_name}! System ${auditModalItem.current_qty} -> Shelf ${pQty}`, 'success'); - setAuditModalItem(null); - handleSearchAudit(auditSearch); - } else { - notify(data.message || 'Failed to reconcile.', 'error'); - } - } catch(e) { - notify('Network error.', 'error'); - } finally { - setIsSubmittingAudit(false); - } - }; - - // Purchase Invoice Photo Capture - const handleCaptureFile = (e) => { - const file = e.target.files && e.target.files[0]; - if (file) { - const reader = new FileReader(); - reader.onload = (evt) => { - setCapturedImageBase64(evt.target.result); - }; - reader.readAsDataURL(file); - } - }; - - const handleUploadPhoto = async () => { - if (!selectedPurchaseId || !capturedImageBase64) { - notify('Please select an inward purchase and take/select a photo.', 'error'); - return; - } - - setIsUploadingPhoto(true); - try { - const res = await fetch(API_BASE + 'purchase/upload-photo', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - purchase_id: Number(selectedPurchaseId), - image_data: capturedImageBase64 - }) - }); - const data = await res.json(); - if (data.status) { - notify('Purchase paper invoice photo attached successfully!', 'success'); - setCapturedImageBase64(null); - loadRecentPurchases(); - } else { - notify(data.message || 'Failed to attach photo.', 'error'); - } - } catch(e) { - notify('Network error uploading photo: ' + e.message, 'error'); - } finally { - setIsUploadingPhoto(false); - } - }; - - return ( -
- {/* Top Sticky App Header */} -
-
-
- -
-
-
{store.store_name}
- - {activeOperator ? activeOperator.full_name : 'Staff'} - -
-
- -
- - - -
-
- - {/* Main Content Area */} -
- - {/* ========================================================================= */} - {/* 1. ADMIN DASHBOARD & HEALTH METRICS */} - {/* ========================================================================= */} - {mobTab === 'dashboard' && ( -
-
-
- Pharmacy Health Dashboard -
- -
- - {loadingDash || !dashData ? ( -
-
-
Loading store telemetry...
-
- ) : ( -
- {/* KPI Tiles */} -
-
-
- TOTAL BATCHES - {dashData.summary?.total_batches || 0} - ({dashData.summary?.total_units || 0} Units) -
-
-
-
- STOCK VALUATION (PTR) - ₹{Number(dashData.summary?.cost_valuation || 0).toLocaleString('en-IN')} -
-
-
-
- NEAR EXPIRY (<90d) - {dashData.summary?.near_expiry_count || 0} Batches -
-
-
-
- SUPPLIER PENDING - ₹{Number(dashData.summary?.total_supplier_pending || 0).toLocaleString('en-IN')} -
-
-
- - {/* Section 1: Nearest Expiry Alert List */} -
-
- - Nearest Expiry Batches - - Priority Action -
-
- {dashData.near_expiry?.length === 0 ? ( -
No batches expiring in next 90 days.
- ) : ( - dashData.near_expiry.map((item, i) => ( -
-
-
{item.item_name}
-
- Batch: {item.batch_no} {item.shelf_no ? `• Sh: ${item.shelf_no}` : ''} -
-
-
- - Exp: {item.expiry_date} - -
{item.current_qty} Units
-
-
- )) - )} -
-
- - {/* Section 2: High Sale Products (Top Movers) */} -
-
- - Fast Moving Medicines - - Top Sales -
-
- {dashData.high_sales?.length === 0 ? ( -
No sale records yet.
- ) : ( - dashData.high_sales.map((item, i) => ( -
-
-
#{i+1} {item.item_name}
-
{item.generic_name || 'Allopathic'}
-
-
- {item.total_sold} Units Sold -
₹{item.total_revenue}
-
-
- )) - )} -
-
- - {/* Section 3: Dump Stock (Dead Stock) */} -
-
- - Dead / Dump Stock (>60d No Movement) - - Capital Blocked -
-
- {dashData.dump_stock?.length === 0 ? ( -
No stagnant stock detected.
- ) : ( - dashData.dump_stock.map((item, i) => ( -
-
-
{item.item_name}
-
Batch: {item.batch_no} • Exp: {item.expiry_date}
-
-
- {item.current_qty} Units Stagnant -
MRP: ₹{item.mrp}
-
-
- )) - )} -
-
- - {/* Section 4: Supplier Pending Dues */} -
-
- - Supplier Payments Pending - - Accounts Payable -
-
- {dashData.supplier_pending?.length === 0 ? ( -
All supplier bills are settled!
- ) : ( - dashData.supplier_pending.map((item, i) => ( -
-
-
{item.supplier_name || 'Distributor'}
-
Inv: {item.supplier_invoice_no} • Due: {item.due_date}
-
-
- ₹{Number(item.pending_amount).toFixed(2)} - Paid: ₹{item.paid_amount} -
-
- )) - )} -
-
-
- )} -
- )} - - {/* ========================================================================= */} - {/* 2. RACK COLLECTOR (MOBILE DRAFT BILL CREATOR) */} - {/* ========================================================================= */} - {mobTab === 'collector' && ( -
-
-
- Shelf & Rack Collector -
- - {collectorItems.length} Items in Basket - -
-

- Collect medicines from shelves, add to mobile basket, and tap "Save Draft" so the cashier on counter PC can bill it immediately. -

- - {/* Search Medicine */} -
- -
- - handleSearchItems(e.target.value)} - /> -
- - {/* Search Dropdown */} - {searchResults.length > 0 && ( -
- {searchResults.map(item => ( -
{ - setSelectedItem(item); - setSelectedBatch(item.batches && item.batches[0] ? item.batches[0] : null); - setSearchResults([]); - }} - style={{ cursor: 'pointer' }} - > -
{item.item_name}
- - {item.generic_name} • Stock: {item.total_stock} Units - -
- ))} -
- )} -
- - {/* Selected Item Detail & Batch Selector */} - {selectedItem && ( -
-
{selectedItem.item_name}
- {selectedItem.generic_name} - -
-
- - -
-
- - -
-
- -
- - setCollectQty(Math.max(1, Number(e.target.value)))} - /> - -
-
-
- -
- - -
-
- )} - - {/* Current Basket Items List */} -
-
- Draft Basket Items ({collectorItems.length}) - {collectorItems.length > 0 && ( - - )} -
-
- {collectorItems.length === 0 ? ( -
- - No medicines collected yet. Search and pick items above. -
- ) : ( - collectorItems.map((it, idx) => ( -
-
-
{it.item_name}
-
- Batch: {it.batch_no} • Qty: {it.qty} {it.sell_unit} • Rate: ₹{it.effective_rate} • Total: ₹{it.line_gross} -
-
- -
- )) - )} -
-
- - {/* Patient & Bed Reference Info */} - {collectorItems.length > 0 && ( -
- -
-
- setPatientName(e.target.value)} - /> -
-
- setPatientMobile(e.target.value)} - /> -
-
- setBedNo(e.target.value)} - /> -
-
- setWardName(e.target.value)} - /> -
-
- - -
- )} -
- )} - - {/* ========================================================================= */} - {/* 3. MOBILE STOCK AUDITOR */} - {/* ========================================================================= */} - {mobTab === 'auditor' && ( -
-
-
- Mobile Shelf Auditor -
- Routine Count -
-

- During low workload hours, search medicine or rack, check shelf count against system records, and reconcile stock with 1 tap. -

- -
- - handleSearchAudit(e.target.value)} - /> -
- -
- {auditResults.length === 0 ? ( -
- Type medicine or batch to verify shelf stock. -
- ) : ( - auditResults.map((item, idx) => ( -
-
-
-
{item.item_name}
-
- Batch: {item.batch_no} • Exp: {item.expiry_display || item.expiry_date} -
-
- - {item.shelf_no ? `Shelf: ${item.shelf_no}` : 'Normal'} - -
- -
-
- SYSTEM STOCK - {item.current_qty} Units -
- -
-
- )) - )} -
- - {/* Single Item Reconcile Modal in Mobile */} - {auditModalItem && ( -
-
-
-
-
Reconcile: {auditModalItem.item_name}
- -
-
-
-
-
- System Qty - {auditModalItem.current_qty} -
-
-
-
- Physical Count - setAuditCount(e.target.value)} - autoFocus - /> -
-
-
- - {(() => { - const sys = Number(auditModalItem.current_qty); - const phy = Number(auditCount !== '' ? auditCount : sys); - const diff = phy - sys; - const rate = Number(auditModalItem.ptr || auditModalItem.mrp || 0); - const val = Math.abs(diff) * rate; - - if (diff === 0) { - return
✓ Counts match (0 diff).
; - } else if (diff < 0) { - return ( -
- Shortage: {Math.abs(diff)} units (Loss: ₹{val.toFixed(2)}) -
- ); - } else { - return ( -
- Surplus: +{diff} units (Valuation: ₹{val.toFixed(2)}) -
- ); - } - })()} - -
- - -
- -
- - setAuditRemarks(e.target.value)} - /> -
-
-
- - -
-
-
-
- )} -
- )} - - {/* ========================================================================= */} - {/* 4. PURCHASE INWARD PAPER INVOICE CAMERA ATTACHMENT */} - {/* ========================================================================= */} - {mobTab === 'purchase_photo' && ( -
-
-
- Inward Bill Camera Attachment -
- Audit Proof -
-

- Take a direct photo of the distributor's delivery challan or paper tax invoice and attach it to the inward record. -

- -
- - - - -
- -
- - {/* Captured Photo Preview */} - {capturedImageBase64 && ( -
-
Preview of Captured Bill:
- Captured Invoice -
- )} - - -
- - {/* View Attached Invoices */} -
-
- Recent Purchases with Photo Status -
-
- {recentPurchases.slice(0, 5).map(p => ( -
-
-
{p.supplier_invoice_no}
-
{p.supplier_name || 'Distributor'} • ₹{p.net_amount}
-
-
- {p.invoice_photo ? ( - - View Photo - - ) : ( - No Photo - )} -
-
- ))} -
-
-
- )} -
- - {/* Bottom Fixed Navigation Bar */} -
- - - - - - - -
-
- ); -} - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - + diff --git a/public/App/MedicalStore/medicalstore-app.bundle.js b/public/App/MedicalStore/medicalstore-app.bundle.js new file mode 100644 index 0000000..cbac7b6 --- /dev/null +++ b/public/App/MedicalStore/medicalstore-app.bundle.js @@ -0,0 +1,20275 @@ +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +const { + useState, + useEffect, + useRef, + useMemo, + useCallback +} = React; +const API_BASE = '/api/v1/medical-store/'; + +// Detect store slug from URL (e.g. /MedicalStore/storeA or /app/medical-store/storeB) +function getInitialStoreSlug() { + if (window.INITIAL_STORE_SLUG) { + return window.INITIAL_STORE_SLUG; + } + const path = window.location.pathname; + const match = path.match(/(?:MedicalStore|app\/medical-store)\/([a-zA-Z0-9_\-]+)/i); + return match ? match[1] : null; +} + +// ========================================================================= +// ROOT ERROR BOUNDARY +// ========================================================================= +class ErrorBoundary extends React.Component { + constructor(props) { + super(props); + this.state = { + hasError: false, + error: null + }; + } + static getDerivedStateFromError(error) { + return { + hasError: true, + error + }; + } + componentDidCatch(error, errorInfo) { + console.error("Medical Store UI Error:", error, errorInfo); + } + render() { + if (this.state.hasError) { + return /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-column align-items-center justify-content-center vh-100 bg-slate-900 text-white p-4 text-center", + style: { + background: '#0f172a' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "bg-danger text-white rounded-circle p-3 mb-3 d-flex align-items-center justify-content-center", + style: { + width: 64, + height: 64 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-octagon fs-2" + }) + }), /*#__PURE__*/_jsx("h4", { + className: "fw-bold", + children: "Counter Desk Interruption" + }), /*#__PURE__*/_jsx("p", { + className: "text-secondary mb-3", + style: { + maxWidth: 500 + }, + children: this.state.error?.message || 'An unexpected error occurred while rendering the counter desk.' + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-light btn-sm", + onClick: () => window.location.reload(), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise me-1" + }), " Reload Counter Desk"] + })] + }); + } + return this.props.children; + } +} +function App() { + const [stores, setStores] = useState([]); + const [activeStoreId, setActiveStoreId] = useState(null); + const [activeTab, setActiveTab] = useState('pos'); // pos, invoices, inventory, purchase, transfer, ledgers + const [editInvoiceForPos, setEditInvoiceForPos] = useState(null); + const [notification, setNotification] = useState(null); + const [isLoadingStores, setIsLoadingStores] = useState(true); + + // Mobile Companion Mode & PWA Installation State + const [isMobileMode, setIsMobileMode] = useState(() => { + const urlParams = new URLSearchParams(window.location.search); + return urlParams.get('mode') === 'mobile' || window.innerWidth <= 768 && !urlParams.get('desktop'); + }); + const [showQrModal, setShowQrModal] = useState(false); + const [serverNetworkInfo, setServerNetworkInfo] = useState(null); + const [selectedLanIp, setSelectedLanIp] = useState(''); + const [pwaInstallPrompt, setPwaInstallPrompt] = useState(null); + + // Active Store Operator / Staff Session State + const [activeOperator, setActiveOperator] = useState(() => { + try { + const saved = localStorage.getItem('mst_active_operator'); + return saved ? JSON.parse(saved) : null; + } catch (e) { + return null; + } + }); + const [storeUsers, setStoreUsers] = useState([]); + const [showOperatorModal, setShowOperatorModal] = useState(false); + const [selectedUserToSwitch, setSelectedUserToSwitch] = useState(null); + const [operatorPinInput, setOperatorPinInput] = useState(''); + const [pinError, setPinError] = useState(''); + const [isSwitchingOperator, setIsSwitchingOperator] = useState(false); + + // Machine Authorization State + const [isDeviceAuthorized, setIsDeviceAuthorized] = useState(false); + const [deviceToken, setDeviceToken] = useState(''); + const [machineName, setMachineName] = useState('Counter PC ' + (navigator.platform || 'Desktop')); + const [secKeyInput, setSecKeyInput] = useState(''); + const [verifyMethod, setVerifyMethod] = useState('key'); // 'key' or 'otp' + const [isVerifying, setIsVerifying] = useState(false); + const storeSlugFromUrl = getInitialStoreSlug(); + + // Active Store Object + const activeStore = stores.find(s => s.store_id == activeStoreId) || stores[0] || null; + useEffect(() => { + fetchStores(); + }, []); + useEffect(() => { + if (activeStore) { + checkMachineAuthorization(activeStore.store_id); + loadStoreUsers(activeStore.store_id); + loadServerNetworkInfo(); + } + const handleInstallPrompt = e => { + e.preventDefault(); + setPwaInstallPrompt(e); + }; + window.addEventListener('beforeinstallprompt', handleInstallPrompt); + return () => window.removeEventListener('beforeinstallprompt', handleInstallPrompt); + }, [activeStoreId, stores]); + const loadServerNetworkInfo = async () => { + try { + const res = await fetch(`${API_BASE}server-info`); + const data = await res.json(); + if (data.status) { + setServerNetworkInfo(data); + setSelectedLanIp(data.primary_ip || window.location.hostname); + } + } catch (e) { + console.error("Failed to load server network info:", e); + } + }; + const triggerPwaInstall = async () => { + if (!pwaInstallPrompt) { + notify('To install on mobile, tap your browser menu (⋮ or Share) and select "Add to Home screen".', 'info'); + return; + } + pwaInstallPrompt.prompt(); + const choice = await pwaInstallPrompt.userChoice; + if (choice.outcome === 'accepted') { + notify('Pharmacy Application installed successfully!', 'success'); + setPwaInstallPrompt(null); + } + }; + const loadStoreUsers = async storeId => { + if (!storeId) return; + try { + const res = await fetch(`${API_BASE}users?store_id=${storeId}`); + const data = await res.json(); + if (data.status && Array.isArray(data.users)) { + setStoreUsers(data.users); + if (!activeOperator || activeOperator.store_id != storeId && activeOperator.store_id != 0) { + const def = data.users.find(u => u.is_default == 1) || data.users[0]; + if (def) { + setActiveOperator(def); + localStorage.setItem('mst_active_operator', JSON.stringify(def)); + } + } + } + } catch (e) { + console.error("Failed to load store staff:", e); + } + }; + const handleSwitchOperator = async () => { + if (!selectedUserToSwitch) return; + if (!operatorPinInput.trim()) { + setPinError('Please enter 4-digit PIN'); + return; + } + setIsSwitchingOperator(true); + setPinError(''); + try { + const res = await fetch(`${API_BASE}users/switch-operator`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: activeStore?.store_id || 1, + user_id: selectedUserToSwitch.user_id, + pin_code: operatorPinInput.trim() + }) + }); + const data = await res.json(); + if (data.status && data.operator) { + setActiveOperator(data.operator); + localStorage.setItem('mst_active_operator', JSON.stringify(data.operator)); + notify(`Switched operator to ${data.operator.full_name} (${data.operator.user_role})`, 'success'); + setShowOperatorModal(false); + setSelectedUserToSwitch(null); + setOperatorPinInput(''); + } else { + setPinError(data.message || 'Incorrect PIN code'); + } + } catch (e) { + setPinError('Network error while verifying PIN'); + } finally { + setIsSwitchingOperator(false); + } + }; + const fetchStores = async () => { + setIsLoadingStores(true); + try { + const url = storeSlugFromUrl ? `${API_BASE}stores?slug=${encodeURIComponent(storeSlugFromUrl)}` : `${API_BASE}stores`; + const res = await fetch(url); + const data = await res.json(); + if (data.status && data.stores && data.stores.length > 0) { + setStores(data.stores); + // If slug matched specific store, select it (case-insensitive) + if (storeSlugFromUrl) { + const matched = data.stores.find(s => s.store_slug && s.store_slug.toLowerCase() === storeSlugFromUrl.toLowerCase() || s.store_code && s.store_code.toLowerCase() === storeSlugFromUrl.toLowerCase()); + if (matched) { + setActiveStoreId(matched.store_id); + return; + } + } + if (!activeStoreId) { + setActiveStoreId(data.stores[0].store_id); + } + } + } catch (e) { + console.error('Failed to load stores:', e); + } finally { + setIsLoadingStores(false); + } + }; + const checkMachineAuthorization = async storeId => { + const savedToken = localStorage.getItem('mst_device_token_' + storeId); + if (!savedToken) { + setIsDeviceAuthorized(false); + return; + } + try { + const res = await fetch(API_BASE + 'device/check', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: storeId, + device_token: savedToken + }) + }); + const data = await res.json(); + if (data.status && data.authorized) { + setIsDeviceAuthorized(true); + setDeviceToken(savedToken); + if (data.machine_name) setMachineName(data.machine_name); + } else { + localStorage.removeItem('mst_device_token_' + storeId); + setIsDeviceAuthorized(false); + } + } catch (e) { + console.error('Device authorization check error:', e); + } + }; + const submitDeviceVerification = async e => { + e.preventDefault(); + if (!activeStore || !secKeyInput) return; + setIsVerifying(true); + try { + const payload = { + store_id: activeStore.store_id, + store_slug: activeStore.store_slug, + machine_name: machineName, + security_key: verifyMethod === 'key' ? secKeyInput : '', + otp: verifyMethod === 'otp' ? secKeyInput : '' + }; + const res = await fetch(API_BASE + 'device/verify', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const data = await res.json(); + if (data.status && data.device_token) { + localStorage.setItem('mst_device_token_' + activeStore.store_id, data.device_token); + setDeviceToken(data.device_token); + setIsDeviceAuthorized(true); + notify(data.message, 'success'); + } else { + alert(data.message || 'Verification failed. Please check with HMS Admin.'); + } + } catch (e) { + alert('Verification request failed: ' + e.message); + } finally { + setIsVerifying(false); + } + }; + const notify = (msg, type = 'success') => { + setNotification({ + msg, + type + }); + setTimeout(() => setNotification(null), 4000); + }; + if (isLoadingStores && !activeStore) { + return /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-column align-items-center justify-content-center vh-100 bg-slate-900 text-white", + style: { + background: '#0f172a' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border text-info mb-3", + style: { + width: '3rem', + height: '3rem' + }, + role: "status", + children: /*#__PURE__*/_jsx("span", { + className: "visually-hidden", + children: "Loading Store Counter..." + }) + }), /*#__PURE__*/_jsx("h5", { + className: "fw-bold tracking-wide", + children: "HMS Multi-Building Medical Store" + }), /*#__PURE__*/_jsx("p", { + className: "text-secondary small", + children: "Synchronizing pharmacy counters, terminal licenses & ABDM..." + })] + }); + } + if (!activeStore) { + return /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-column align-items-center justify-content-center vh-100 bg-slate-900 text-white p-4 text-center", + style: { + background: '#0f172a' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "bg-danger text-white rounded-circle p-3 mb-3 d-flex align-items-center justify-content-center", + style: { + width: 64, + height: 64 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle fs-2" + }) + }), /*#__PURE__*/_jsx("h4", { + className: "fw-bold", + children: "Medical Store Not Found" + }), /*#__PURE__*/_jsxs("p", { + className: "text-secondary mb-3", + style: { + maxWidth: 480 + }, + children: ["Could not locate any active pharmacy store counter for ", /*#__PURE__*/_jsxs("code", { + children: ["/", storeSlugFromUrl || 'default'] + }), ". Please verify store configuration in HMS Admin."] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("a", { + href: "/MedicalStore/storeA", + className: "btn btn-outline-light btn-sm", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shop me-1" + }), " Try Main Store (storeA)"] + }), /*#__PURE__*/_jsxs("a", { + href: "/app/admin/medical-stores", + className: "btn btn-primary-custom btn-sm", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-gear me-1" + }), " Open HMS Store Settings"] + })] + })] + }); + } + return /*#__PURE__*/_jsxs("div", { + children: [!isDeviceAuthorized && activeStore && /*#__PURE__*/_jsx("div", { + className: "machine-lock-backdrop", + children: /*#__PURE__*/_jsxs("div", { + className: "card shadow-lg border-0", + style: { + maxWidth: 460, + width: '100%', + borderRadius: 16 + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-dark text-white p-3 text-center border-0", + style: { + borderTopLeftRadius: 16, + borderTopRightRadius: 16 + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-lock-fill text-warning fs-1 d-block mb-1" + }), /*#__PURE__*/_jsx("h5", { + className: "fw-bold mb-0", + children: "Terminal Machine Verification" + }), /*#__PURE__*/_jsx("small", { + className: "text-slate-300", + style: { + color: '#94a3b8' + }, + children: "Counter Authorization Required" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card-body p-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "text-center mb-3", + children: [/*#__PURE__*/_jsx("h6", { + className: "fw-bold text-dark", + children: activeStore.store_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-geo-alt me-1" + }), activeStore.building_name || 'Main Hospital', " • ", activeStore.floor_no || 'Ground Floor'] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle px-2 py-1 mt-1", + children: ["Link: MedicalStore/", activeStore.store_slug] + })] + }), /*#__PURE__*/_jsxs("p", { + className: "small text-muted text-center mb-3", + children: ["This computer terminal is accessing the counter for the first time. Please enter the ", /*#__PURE__*/_jsx("strong", { + children: "Security Key" + }), " or ", /*#__PURE__*/_jsx("strong", { + children: "6-digit OTP" + }), " provided by HMS Admin."] + }), /*#__PURE__*/_jsxs("form", { + onSubmit: submitDeviceVerification, + children: [/*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-dark mb-1", + children: "Computer / Machine Name" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: machineName, + onChange: e => setMachineName(e.target.value), + required: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm w-100 mb-2", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${verifyMethod === 'key' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setVerifyMethod('key'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-key-fill me-1" + }), " Admin Security Key"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${verifyMethod === 'otp' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setVerifyMethod('otp'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-123 me-1" + }), " 6-Digit Counter OTP"] + })] + }), /*#__PURE__*/_jsx("input", { + type: verifyMethod === 'otp' ? 'number' : 'text', + className: "form-control text-center fw-bold fs-5 letter-spacing-1", + placeholder: verifyMethod === 'key' ? 'e.g. HMS-XXXXXX-XXX' : 'Enter 6-digit OTP', + value: secKeyInput, + onChange: e => setSecKeyInput(e.target.value), + required: true + })] + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-success-custom w-100 py-2.5 mt-3 fw-bold", + disabled: isVerifying, + children: isVerifying ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split me-1" + }), " Verifying Terminal..."] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " Verify Machine & Unlock Counter"] + }) + })] + })] + })] + }) + }), /*#__PURE__*/_jsx("header", { + className: "navbar-store", + children: /*#__PURE__*/_jsxs("div", { + className: "container-fluid d-flex flex-wrap align-items-center justify-content-between gap-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-3", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-primary text-white p-2 rounded-3 d-flex align-items-center justify-content-center", + style: { + width: 40, + height: 40 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-capsule fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold text-white fs-5", + children: activeStore ? activeStore.store_name : 'Medical Store Counter' + }), activeStore && /*#__PURE__*/_jsxs("span", { + className: "badge bg-info-subtle text-info border border-info px-2 py-0.5 rounded-pill", + style: { + fontSize: '0.65rem' + }, + children: ["/", activeStore.store_slug || activeStore.store_code] + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-geo-alt me-1" + }), activeStore ? `${activeStore.building_name || 'Main Building'} • ${activeStore.floor_no || 'Ground Floor'}` : 'Counter'] + })] + })] + }), activeStore && /*#__PURE__*/_jsxs("div", { + className: "d-none d-md-flex align-items-center gap-2", + children: [activeStore.abdm_hfr_id && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success px-2 py-1", + title: "ABDM Health Facility Registry", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check me-1" + }), " HFR: ", activeStore.abdm_hfr_id] + }), /*#__PURE__*/_jsxs("span", { + className: "badge-license", + title: "Retail Allopathic Drug License", + children: ["DL 20B: ", activeStore.drug_license_no_20b || 'N/A'] + }), /*#__PURE__*/_jsxs("span", { + className: "badge-license", + title: "Schedule C/C1 Drug License", + children: ["DL 21B: ", activeStore.drug_license_no_21b || 'N/A'] + }), /*#__PURE__*/_jsxs("span", { + className: "badge-gst", + title: "GSTIN", + children: ["GSTIN: ", activeStore.gstin || 'N/A'] + }), isDeviceAuthorized && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success text-white rounded-pill px-2.5 py-1", + style: { + fontSize: '0.7rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " Terminal Verified"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm text-white d-flex align-items-center gap-2 px-3 py-1.5 rounded-pill shadow-sm", + style: { + background: 'linear-gradient(135deg, rgba(14, 165, 233, 0.25), rgba(99, 102, 241, 0.25))', + border: '1px solid rgba(56, 189, 248, 0.5)', + backdropFilter: 'blur(4px)' + }, + onClick: () => { + setSelectedUserToSwitch(activeOperator || storeUsers[0] || null); + setOperatorPinInput(''); + setPinError(''); + setShowOperatorModal(true); + }, + title: "Active Medical Store Operator / Cashier (Click to switch)", + children: [/*#__PURE__*/_jsx("div", { + className: "rounded-circle bg-info text-dark d-flex align-items-center justify-content-center fw-bold", + style: { + width: 26, + height: 26, + fontSize: '0.75rem' + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge-fill" + }) + }), /*#__PURE__*/_jsxs("div", { + className: "text-start lh-1", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white text-truncate", + style: { + maxWidth: 130 + }, + children: activeOperator ? activeOperator.full_name : 'Select Staff' + }), /*#__PURE__*/_jsx("span", { + className: "badge p-0 text-cyan-300", + style: { + fontSize: '0.65rem', + color: '#7dd3fc' + }, + children: activeOperator ? activeOperator.user_role.toUpperCase() : 'COUNTER' + })] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-dark bg-opacity-50 text-white-50 px-1.5 py-0.5 rounded small", + style: { + fontSize: '0.65rem' + }, + children: ["Switch ", /*#__PURE__*/_jsx("i", { + className: "bi bi-key-fill text-warning ms-0.5" + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1.5 px-3 py-1.5 rounded-pill border border-secondary shadow-xs text-white", + style: { + background: '#1e293b', + fontSize: '0.78rem' + }, + title: "Active counter store is locked for billing integrity", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital text-info" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + children: activeStore ? activeStore.store_name : 'Counter' + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary-subtle text-secondary py-0.5 px-1.5 rounded", + style: { + fontSize: '0.62rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-lock-fill me-0.5 text-warning" + }), " LOCKED"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm text-white rounded-pill px-2.5 py-1 d-flex align-items-center gap-1.5 shadow-sm", + style: { + background: 'rgba(14, 165, 233, 0.2)', + border: '1px solid #0ea5e9' + }, + onClick: () => setShowQrModal(true), + title: "Scan QR Code to open Mobile Rack Collector & Stock Auditor on phone", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-qr-code text-cyan-300" + }), /*#__PURE__*/_jsx("span", { + className: "d-none d-lg-inline small fw-semibold", + children: "Mobile App QR" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm rounded-pill px-2.5 py-1 d-flex align-items-center gap-1.5 ${isMobileMode ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => setIsMobileMode(!isMobileMode), + title: "Toggle Mobile Companion View", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone" + }), /*#__PURE__*/_jsx("span", { + className: "small fw-semibold", + children: isMobileMode ? 'Desktop' : 'Mobile' + })] + }), /*#__PURE__*/_jsx("a", { + href: "/app", + className: "btn btn-sm btn-outline-light", + title: "Return to App Hub", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-grid-fill" + }) + })] + })] + }) + }), notification && /*#__PURE__*/_jsxs("div", { + className: `position-fixed shadow-lg alert alert-${notification.type === 'error' ? 'danger' : notification.type === 'warning' ? 'warning' : 'success'} d-flex align-items-center gap-2 alert-dismissible fade show m-0 py-2.5 px-3`, + style: { + top: '1.25rem', + right: '1.5rem', + zIndex: 999999, + minWidth: '320px', + maxWidth: '480px', + borderWidth: '1.5px', + borderRadius: '10px' + }, + role: "alert", + children: [/*#__PURE__*/_jsx("i", { + className: `bi bi-${notification.type === 'error' ? 'exclamation-triangle-fill' : notification.type === 'warning' ? 'exclamation-circle-fill' : 'check-circle-fill'} fs-5 me-1` + }), /*#__PURE__*/_jsx("div", { + className: "flex-grow-1 fw-semibold small pe-2", + children: notification.msg + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close p-2", + onClick: () => setNotification(null) + })] + }), /*#__PURE__*/_jsxs("nav", { + className: "nav-tabs-custom d-flex flex-wrap", + children: [/*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'pos' ? 'active' : ''}`, + onClick: () => setActiveTab('pos'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart3 me-1" + }), " POS Counter Desk"] + }), /*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'invoices' ? 'active' : ''}`, + onClick: () => setActiveTab('invoices'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt me-1" + }), " All Invoices & Sales"] + }), /*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'inventory' ? 'active' : ''}`, + onClick: () => setActiveTab('inventory'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-boxes me-1" + }), " Live Stock & Batches"] + }), /*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'purchase' ? 'active' : ''}`, + onClick: () => setActiveTab('purchase'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-down me-1" + }), " Purchases & Stock Import"] + }), /*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'transfer' ? 'active' : ''}`, + onClick: () => setActiveTab('transfer'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left-right me-1" + }), " Inter-Store Indents"] + }), /*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'ledgers' ? 'active' : ''}`, + onClick: () => setActiveTab('ledgers'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-text me-1" + }), " Ledgers, Daybook & GST"] + }), /*#__PURE__*/_jsxs("button", { + className: `nav-link ${activeTab === 'staff' ? 'active' : ''}`, + onClick: () => setActiveTab('staff'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-people-fill me-1" + }), " Staff & Roles"] + })] + }), isMobileMode ? /*#__PURE__*/_jsx(MobileAppView, { + store: activeStore, + stores: stores, + notify: notify, + activeOperator: activeOperator, + onSwitchOperator: () => setShowOperatorModal(true), + onExitMobile: () => setIsMobileMode(false), + triggerPwaInstall: triggerPwaInstall + }) : /*#__PURE__*/_jsxs("main", { + className: "container-fluid py-3", + children: [activeTab === 'pos' && /*#__PURE__*/_jsx(PosCounter, { + store: activeStore, + notify: notify, + activeOperator: activeOperator, + onSwitchOperator: () => setShowOperatorModal(true), + initialEditInvoice: editInvoiceForPos, + onClearEditInvoice: () => setEditInvoiceForPos(null) + }), activeTab === 'invoices' && /*#__PURE__*/_jsx(InvoicesView, { + store: activeStore, + notify: notify, + activeOperator: activeOperator, + onEditInPos: invData => { + setEditInvoiceForPos(invData); + setActiveTab('pos'); + } + }), activeTab === 'inventory' && /*#__PURE__*/_jsx(InventoryView, { + store: activeStore, + notify: notify, + activeOperator: activeOperator + }), activeTab === 'purchase' && /*#__PURE__*/_jsx(PurchaseView, { + store: activeStore, + notify: notify, + activeOperator: activeOperator + }), activeTab === 'transfer' && /*#__PURE__*/_jsx(TransferView, { + store: activeStore, + stores: stores, + notify: notify, + activeOperator: activeOperator + }), activeTab === 'ledgers' && /*#__PURE__*/_jsx(LedgersView, { + store: activeStore, + notify: notify, + activeOperator: activeOperator + }), activeTab === 'staff' && /*#__PURE__*/_jsx(StaffManagementView, { + store: activeStore, + notify: notify, + activeOperator: activeOperator, + onOperatorUpdated: () => loadStoreUsers(activeStore?.store_id), + onSelectOperator: u => { + setSelectedUserToSwitch(u); + setOperatorPinInput(''); + setPinError(''); + setShowOperatorModal(true); + } + })] + }), showQrModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.85)', + zIndex: 10700 + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + style: { + maxWidth: 520 + }, + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-2xl rounded-4 overflow-hidden", + style: { + background: '#0f172a', + color: '#f8fafc', + border: '1px solid #334155' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header border-bottom border-secondary py-3 px-4", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "p-2 rounded-3 bg-info bg-opacity-25 text-info", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-qr-code-scan fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold text-white mb-0", + children: "Mobile App QR & Installation" + }), /*#__PURE__*/_jsxs("small", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: [activeStore?.store_name, " • Rack Collector & Stock Auditor"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowQrModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-4 text-center", + children: [serverNetworkInfo && serverNetworkInfo.detected_ips && serverNetworkInfo.detected_ips.length > 1 && /*#__PURE__*/_jsxs("div", { + className: "mb-3 text-start", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold text-uppercase", + style: { + color: '#cbd5e1' + }, + children: "Hospital WiFi / LAN IP" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm bg-dark text-white border-secondary", + value: selectedLanIp, + onChange: e => setSelectedLanIp(e.target.value), + children: [serverNetworkInfo.detected_ips.map(ip => /*#__PURE__*/_jsxs("option", { + value: ip, + children: [ip, " (WiFi / LAN Network)"] + }, ip)), /*#__PURE__*/_jsxs("option", { + value: window.location.hostname, + children: [window.location.hostname, " (Current Browser Host)"] + })] + })] + }), (() => { + const portStr = serverNetworkInfo?.port ? ':' + serverNetworkInfo.port : window.location.port ? ':' + window.location.port : ''; + const hostIp = selectedLanIp || serverNetworkInfo?.primary_ip || window.location.hostname; + const targetUrl = `http://${hostIp}${portStr}/MedicalStore/${activeStore?.store_slug || 'storea'}?mode=mobile`; + const qrSrc = `https://api.qrserver.com/v1/create-qr-code/?size=240x240&margin=8&data=${encodeURIComponent(targetUrl)}`; + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "p-3 bg-white rounded-4 shadow d-inline-block mb-3", + children: /*#__PURE__*/_jsx("img", { + src: qrSrc, + alt: "Scan to open Mobile Pharmacy App", + style: { + width: 220, + height: 220, + display: 'block' + } + }) + }), /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 mb-3 text-start small border border-secondary", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "text-slate-400 small mb-1", + style: { + color: '#94a3b8' + }, + children: "Mobile Application URL:" + }), /*#__PURE__*/_jsx("div", { + className: "fw-mono text-cyan-300 text-truncate fw-bold", + style: { + color: '#67e8f9' + }, + children: targetUrl + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 text-start small mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2 rounded-3 border border-secondary text-center h-100", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-info mb-1", + children: "1. Scan QR" + }), /*#__PURE__*/_jsx("div", { + className: "text-slate-400", + style: { + fontSize: '0.72rem', + color: '#94a3b8' + }, + children: "Open camera app on your smartphone" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2 rounded-3 border border-secondary text-center h-100", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-info mb-1", + children: "2. Rack Drafts" + }), /*#__PURE__*/_jsx("div", { + className: "text-slate-400", + style: { + fontSize: '0.72rem', + color: '#94a3b8' + }, + children: "Collect items & audit shelf stock" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2 rounded-3 border border-secondary text-center h-100", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-success mb-1", + children: "3. Install App" + }), /*#__PURE__*/_jsx("div", { + className: "text-slate-400", + style: { + fontSize: '0.72rem', + color: '#94a3b8' + }, + children: "Tap \"Add to Home Screen\" to install" + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-center gap-2", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-info d-flex align-items-center gap-1.5", + onClick: () => { + navigator.clipboard.writeText(targetUrl); + notify('Mobile app URL copied to clipboard!', 'success'); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-copy" + }), " Copy Link"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-success d-flex align-items-center gap-1.5", + onClick: triggerPwaInstall, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone-fill" + }), " 📲 Install App"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-primary d-flex align-items-center gap-1.5 fw-bold", + onClick: () => { + setIsMobileMode(true); + setShowQrModal(false); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-right-circle" + }), " Open Mobile Mode"] + })] + })] + }); + })()] + })] + }) + }) + }), showOperatorModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)', + zIndex: 10600 + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + style: { + maxWidth: 500 + }, + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-2xl rounded-4 overflow-hidden", + style: { + background: '#0f172a', + color: '#f8fafc', + border: '1px solid #334155' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header border-bottom border-secondary py-3 px-4", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "p-2 rounded-3 bg-primary bg-opacity-25 text-primary", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge-fill fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold text-white mb-0", + children: "Switch Store Operator / Auditor" + }), /*#__PURE__*/_jsxs("small", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: [activeStore?.store_name, " • Counter Session"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowOperatorModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold text-uppercase", + style: { + color: '#cbd5e1' + }, + children: "1. Select Staff Member" + }), /*#__PURE__*/_jsx("div", { + className: "d-flex flex-column gap-2 mb-3", + style: { + maxHeight: 220, + overflowY: 'auto' + }, + children: storeUsers.map(u => { + const isSelected = selectedUserToSwitch?.user_id == u.user_id; + const isCurrent = activeOperator?.user_id == u.user_id; + return /*#__PURE__*/_jsxs("div", { + onClick: () => { + setSelectedUserToSwitch(u); + setPinError(''); + setOperatorPinInput(''); + }, + className: `p-2.5 rounded-3 d-flex align-items-center justify-content-between cursor-pointer transition-all ${isSelected ? 'border border-primary' : 'border border-secondary'}`, + style: { + background: isSelected ? 'rgba(14, 165, 233, 0.15)' : '#1e293b', + cursor: 'pointer' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2.5", + children: [/*#__PURE__*/_jsx("div", { + className: "rounded-circle bg-dark text-cyan-400 border border-slate-700 d-flex align-items-center justify-content-center fw-bold", + style: { + width: 34, + height: 34, + fontSize: '0.85rem' + }, + children: u.full_name ? u.full_name[0] : 'U' + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-white small d-flex align-items-center gap-1.5", + children: [u.full_name, isCurrent && /*#__PURE__*/_jsx("span", { + className: "badge bg-success", + style: { + fontSize: '0.6rem' + }, + children: "CURRENT" + }), u.is_default == 1 && /*#__PURE__*/_jsx("span", { + className: "badge bg-info-subtle text-info", + style: { + fontSize: '0.6rem' + }, + children: "DEFAULT" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.72rem', + color: '#94a3b8' + }, + children: ["@", u.username, " • ", /*#__PURE__*/_jsx("span", { + className: "text-capitalize text-info", + children: u.user_role.replace('_', ' ') + }), u.pharmacist_reg_no && ` • Reg: ${u.pharmacist_reg_no}`] + })] + })] + }), /*#__PURE__*/_jsx("i", { + className: `bi bi-${isSelected ? 'check-circle-fill text-primary' : 'circle text-secondary'} fs-5` + })] + }, u.user_id); + }) + }), selectedUserToSwitch && /*#__PURE__*/_jsxs("div", { + className: "mt-3 p-3 rounded-3", + style: { + background: '#1e293b', + border: '1px solid #334155' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-2", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label text-slate-300 small fw-bold text-uppercase mb-0", + style: { + color: '#cbd5e1' + }, + children: ["2. Enter 4-Digit Security PIN for ", selectedUserToSwitch.full_name] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-dark text-slate-400 small", + style: { + fontSize: '0.65rem' + }, + children: "Default: 1234/1111" + })] + }), /*#__PURE__*/_jsx("input", { + type: "password", + maxLength: "6", + className: "form-control form-control-lg text-center fw-bold fs-4 tracking-widest bg-dark text-white border-secondary", + placeholder: "••••", + value: operatorPinInput, + onChange: e => { + setOperatorPinInput(e.target.value); + setPinError(''); + }, + onKeyDown: e => { + if (e.key === 'Enter') handleSwitchOperator(); + }, + autoFocus: true + }), pinError && /*#__PURE__*/_jsxs("div", { + className: "text-danger small mt-2 d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-circle-fill" + }), " ", pinError] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer border-top border-secondary py-2 px-4 d-flex justify-content-between", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-info d-flex align-items-center gap-1.5", + onClick: () => { + setShowOperatorModal(false); + setShowQrModal(true); + }, + title: "Scan QR code to open installable mobile application on smartphone", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-qr-code-scan" + }), /*#__PURE__*/_jsx("span", { + children: "📱 Mobile App QR Code" + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setShowOperatorModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-primary px-3 fw-bold d-flex align-items-center gap-1.5", + onClick: handleSwitchOperator, + disabled: isSwitchingOperator || !selectedUserToSwitch || !operatorPinInput, + children: isSwitchingOperator ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm" + }), " Verifying..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-right" + }), " Authenticate & Switch"] + }) + })] + })] + })] + }) + }) + })] + }); +} + +// ========================================================================= +// 1. POS BILLING & DISPENSING COUNTER (MULTI-PRINT: A4, A5, 80mm THERMAL) +// ========================================================================= +function PosCounter({ + store, + notify, + initialEditInvoice, + onClearEditInvoice, + activeOperator, + onSwitchOperator +}) { + if (!store) { + return /*#__PURE__*/_jsxs("div", { + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary me-2" + }), "Loading counter desk..."] + }); + } + const [patientQuery, setPatientQuery] = useState(''); + const [patientResults, setPatientResults] = useState([]); + const [selectedPatient, setSelectedPatient] = useState(null); + const [patientType, setPatientType] = useState('Walk-in'); // Walk-in, OPD, IPD + + const [walkinAbhaId, setWalkinAbhaId] = useState(''); + const [walkinAbhaAddress, setWalkinAbhaAddress] = useState(''); + const [walkinMobile, setWalkinMobile] = useState(''); + const [walkinUhid, setWalkinUhid] = useState(''); + const [showFhirModal, setShowFhirModal] = useState(false); + const [fhirBundleData, setFhirBundleData] = useState(null); + const [isLoadingFhir, setIsLoadingFhir] = useState(false); + const [copiedFhir, setCopiedFhir] = useState(false); + const [doctorName, setDoctorName] = useState(''); + const [doctorRegNo, setDoctorRegNo] = useState(''); + const [itemQuery, setItemQuery] = useState(''); + const [itemResults, setItemResults] = useState([]); + const [isSearchingItems, setIsSearchingItems] = useState(false); + const [cart, setCart] = useState([]); + const [wholeDiscountType, setWholeDiscountType] = useState('pct'); // 'pct' or 'val' + const [wholeDiscountVal, setWholeDiscountVal] = useState(0); + const [paymentMode, setPaymentMode] = useState('Cash'); // Cash, UPI, Card, Mixed, IPD_Credit, Staff_Credit + const [draftBillsList, setDraftBillsList] = useState([]); + const [showDraftModal, setShowDraftModal] = useState(false); + const [draftModalTab, setDraftModalTab] = useState('DRAFT'); // 'DRAFT' or 'CONVERTED' + const [loadedDraft, setLoadedDraft] = useState(null); + const [creditAccounts, setCreditAccounts] = useState([]); + const [selectedCreditAccount, setSelectedCreditAccount] = useState(null); + const loadDraftBills = async statusOverride => { + if (!store?.store_id) return; + try { + const st = statusOverride !== undefined ? statusOverride : 'DRAFT'; + const res = await fetch(`${API_BASE}drafts/list?store_id=${store.store_id}&status=${st}`); + const data = await res.json(); + if (data.status) { + setDraftBillsList(data.drafts || []); + } + } catch (e) { + console.error('Error fetching drafts:', e); + } + }; + const loadCreditAccountsList = async () => { + if (!store?.store_id) return; + try { + const res = await fetch(`${API_BASE}credit/accounts?store_id=${store.store_id}`); + const data = await res.json(); + if (data.status) { + setCreditAccounts(data.accounts || []); + } + } catch (e) { + console.error('Error fetching credit accounts:', e); + } + }; + useEffect(() => { + if (store?.store_id) { + loadDraftBills(); + loadCreditAccountsList(); + const timer = setInterval(loadDraftBills, 25000); + return () => clearInterval(timer); + } + }, [store?.store_id]); + const handleLoadDraftBillIntoCart = draft => { + try { + const rawItems = typeof draft.items_json === 'string' ? JSON.parse(draft.items_json) : draft.items || draft.items_json; + if (!Array.isArray(rawItems) || rawItems.length === 0) { + notify('Draft contains no items.', 'warning'); + return; + } + const formattedCart = rawItems.map((it, idx) => { + const upp = Number(it.units_per_pack) > 0 ? Number(it.units_per_pack) : 1; + const sellUnit = it.sell_unit || (upp > 1 ? 'Tablet' : 'Unit'); + const q = Math.max(1, Number(it.qty) || 1); + + // Resiliently resolve strip MRP (unit_mrp) + let unitMrp = Number(it.unit_mrp ?? it.mrp ?? 0); + if (unitMrp <= 0) { + if (Number(it.effective_rate) > 0) { + unitMrp = sellUnit === 'Tablet' ? Number((Number(it.effective_rate) * upp).toFixed(2)) : Number(it.effective_rate); + } else if (Number(it.line_gross) > 0) { + unitMrp = sellUnit === 'Tablet' ? Number(it.line_gross) : Number((Number(it.line_gross) / q).toFixed(2)); + } + } + const stripQty = sellUnit === 'Strip' ? q : Number(it.strip_qty) || 0; + const looseQty = sellUnit === 'Tablet' || sellUnit === 'Unit' ? q : Number(it.loose_qty) || 0; + return { + ...it, + cart_item_id: Date.now() + '_' + idx + '_' + Math.random().toString(36).substr(2, 4), + item_id: it.item_id, + item_name: it.item_name, + generic_name: it.generic_name || '', + unit_pack: it.unit_pack || (upp > 1 ? `Pack: ${upp} Tabs` : 'Unit'), + units_per_pack: upp, + drug_schedule: it.drug_schedule || '', + hsn_code: it.hsn_code || '3004', + gst_rate: it.gst_rate !== undefined && it.gst_rate !== null ? Number(it.gst_rate) : 12.0, + batch_id: it.batch_id, + batch_no: it.batch_no, + expiry_display: it.expiry_display || (it.expiry_date ? it.expiry_date.substring(0, 7) : ''), + expiry_date: it.expiry_date || '', + current_qty: Number(it.current_qty) || 9999, + unit_mrp: unitMrp, + mrp: unitMrp, + sell_unit: sellUnit, + strip_qty: stripQty, + loose_qty: looseQty, + qty: q, + discount_type: it.discount_type || 'pct', + discount_val: Number(it.discount_val) || 0 + }; + }); + setCart(formattedCart); + setLoadedDraft(draft); + if (draft.patient_name) setPatientQuery(draft.patient_name); + if (draft.uhid) setWalkinUhid(draft.uhid); + if (draft.patient_mobile) setWalkinMobile(draft.patient_mobile); + if (draft.doctor_name) setDoctorName(draft.doctor_name); + setShowDraftModal(false); + notify(`Draft [${draft.draft_code}] with ${rawItems.length} items loaded into billing cart!`, 'success'); + } catch (err) { + notify('Failed to load draft items: ' + err.message, 'error'); + } + }; + const handleCancelDraft = async draftId => { + if (!confirm('Discard this draft bill?')) return; + try { + const res = await fetch(`${API_BASE}drafts/cancel`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + draft_id: draftId + }) + }); + const data = await res.json(); + if (data.status) { + notify('Draft discarded.', 'info'); + loadDraftBills(); + } + } catch (e) { + notify('Error cancelling draft: ' + e.message, 'error'); + } + }; + const [paymentRef, setPaymentRef] = useState(''); + const [splitCash, setSplitCash] = useState(''); + const [splitUpi, setSplitUpi] = useState(''); + const [splitCard, setSplitCard] = useState(''); + const [upiRefNo, setUpiRefNo] = useState(''); + const [bankName, setBankName] = useState(''); + const [cardRefNo, setCardRefNo] = useState(''); + const [lastInvoice, setLastInvoice] = useState(null); + const [printFormat, setPrintFormat] = useState('thermal'); // 'thermal', 'a5', 'a4' + const [isProcessing, setIsProcessing] = useState(false); + const [isCheckoutOpen, setIsCheckoutOpen] = useState(false); + const [isPrintOpen, setIsPrintOpen] = useState(false); + + // Patient History & Old Records State (Right-Side Panel) + const [patientHistory, setPatientHistory] = useState(null); + const [isLoadingHistory, setIsLoadingHistory] = useState(false); + const [showHistoryPanel, setShowHistoryPanel] = useState(true); + const [historyActiveTab, setHistoryActiveTab] = useState('last_given'); // 'last_given', 'all_bills', 'prescriptions', 'summary' + const [expandedBillId, setExpandedBillId] = useState(null); + + // POS Counter Persistent Draft Auto-Save & Recovery + const draftKey = `hms_pharmacy_pos_draft_${store?.store_id || 1}`; + const [draftStatus, setDraftStatus] = useState('idle'); // 'idle', 'saved', 'restored' + const [draftSavedAt, setDraftSavedAt] = useState(null); + const [isRestoredBannerVisible, setIsRestoredBannerVisible] = useState(false); + const [editingInvoiceBanner, setEditingInvoiceBanner] = useState(null); + const isRestoringRef = useRef(false); + + // 1. Handle initialEditInvoice (from Invoices tab "Edit in POS") + useEffect(() => { + if (!initialEditInvoice || !initialEditInvoice.sale) return; + try { + isRestoringRef.current = true; + const sale = initialEditInvoice.sale; + const pt = { + id: sale.patient_id || 0, + patient_id: sale.patient_id || 0, + uhid: sale.uhid || '', + name: sale.patient_name || 'Walk-in Customer', + patient_name: sale.patient_name || 'Walk-in Customer', + mobile: sale.patient_mobile || '', + patient_mobile: sale.patient_mobile || '', + patient_type: sale.patient_type || 'Walk-in', + address: sale.patient_address || '', + age: sale.age || '', + gender: sale.gender || '' + }; + setSelectedPatient(pt); + setPatientType(sale.patient_type || 'Walk-in'); + setDoctorName(sale.doctor_name || ''); + setDoctorRegNo(sale.doctor_reg_no || ''); + if (sale.payment_mode) setPaymentMode(sale.payment_mode); + if (sale.bill_discount_type) setWholeDiscountType(sale.bill_discount_type); + if (sale.bill_discount_val) setWholeDiscountVal(Number(sale.bill_discount_val) || 0); + if (sale.patient_id || sale.uhid) { + fetchPatientHistory(sale.patient_id, sale.uhid, sale.patient_mobile); + setShowHistoryPanel(true); + } + const restoredItems = (initialEditInvoice.items || []).filter(it => (it.item_type || 'SALE') === 'SALE').map(it => { + const unitsPerPack = Math.max(1, Number(it.units_per_pack) || 1); + const sellUnit = it.sell_unit || 'Strip'; + const qty = Number(it.qty) || 1; + return { + item_id: Number(it.item_id), + item_name: it.item_name || 'Medicine', + generic_name: it.generic_name || '', + drug_schedule: it.drug_schedule || '', + unit_pack: it.unit_pack || '', + units_per_pack: unitsPerPack, + batch_id: Number(it.batch_id), + batch_no: it.batch_no || '', + expiry_date: it.expiry_date || '', + qty: qty, + strip_qty: sellUnit === 'Strip' ? qty : 0, + loose_qty: sellUnit === 'Tablet' ? qty : 0, + sell_unit: sellUnit, + mrp: Number(it.unit_mrp) || Number(it.unit_price) || 0, + rate: Number(it.unit_price) || 0, + gst_rate: Number(it.gst_rate) || 0, + discount_pct: Number(it.discount_pct) || 0, + current_qty: 999 + }; + }); + setCart(restoredItems); + setEditingInvoiceBanner(sale.invoice_no); + setIsRestoredBannerVisible(false); + notify(`Loaded invoice ${sale.invoice_no} into POS counter for editing.`, 'success'); + setTimeout(() => { + isRestoringRef.current = false; + }, 400); + } catch (e) { + console.error('Error loading edit invoice:', e); + isRestoringRef.current = false; + } + }, [initialEditInvoice]); + + // 2. Draft Auto-Recovery on Mount (Persistent across computer restart / crash / reload) + useEffect(() => { + if (initialEditInvoice) return; + try { + const rawDraft = localStorage.getItem(draftKey); + if (rawDraft) { + const draft = JSON.parse(rawDraft); + const hasItems = draft.cart && draft.cart.length > 0; + const hasPatient = !!draft.selectedPatient; + const hasReturns = draft.returnCart && draft.returnCart.length > 0; + if (hasItems || hasPatient || hasReturns) { + isRestoringRef.current = true; + if (draft.selectedPatient) { + setSelectedPatient(draft.selectedPatient); + if (draft.selectedPatient.patient_id || draft.selectedPatient.uhid) { + fetchPatientHistory(draft.selectedPatient.patient_id, draft.selectedPatient.uhid, draft.selectedPatient.mobile || draft.selectedPatient.patient_mobile); + setShowHistoryPanel(true); + } + } + if (draft.patientType) setPatientType(draft.patientType); + if (draft.doctorName) setDoctorName(draft.doctorName); + if (draft.doctorRegNo) setDoctorRegNo(draft.doctorRegNo); + if (draft.walkinAbhaId) setWalkinAbhaId(draft.walkinAbhaId); + if (draft.walkinAbhaAddress) setWalkinAbhaAddress(draft.walkinAbhaAddress); + if (hasItems) setCart(draft.cart); + if (hasReturns) setReturnCart(draft.returnCart); + if (draft.wholeDiscountType) setWholeDiscountType(draft.wholeDiscountType); + if (draft.wholeDiscountVal) setWholeDiscountVal(draft.wholeDiscountVal); + if (draft.paymentMode) setPaymentMode(draft.paymentMode); + if (draft.splitCash) setSplitCash(draft.splitCash); + if (draft.splitUpi) setSplitUpi(draft.splitUpi); + if (draft.splitCard) setSplitCard(draft.splitCard); + if (draft.editingInvoiceBanner) setEditingInvoiceBanner(draft.editingInvoiceBanner); + setDraftStatus('restored'); + setDraftSavedAt(draft.timestamp ? new Date(draft.timestamp) : new Date()); + setIsRestoredBannerVisible(true); + setTimeout(() => { + isRestoringRef.current = false; + }, 400); + } + } + } catch (e) { + console.error('Error recovering draft:', e); + isRestoringRef.current = false; + } + }, [store?.store_id]); + + // 3. Debounced Auto-Save to localStorage on state change + useEffect(() => { + if (isRestoringRef.current) return; + const hasData = cart && cart.length > 0 || selectedPatient || returnCart && returnCart.length > 0 || doctorName && doctorName.trim().length > 0; + if (!hasData) { + if (!editingInvoiceBanner) { + try { + localStorage.removeItem(draftKey); + } catch (e) {} + setDraftStatus('idle'); + } + return; + } + const timer = setTimeout(() => { + try { + const draftData = { + timestamp: Date.now(), + selectedPatient, + patientType, + doctorName, + doctorRegNo, + walkinAbhaId, + walkinAbhaAddress, + cart, + returnCart, + wholeDiscountType, + wholeDiscountVal, + paymentMode, + splitCash, + splitUpi, + splitCard, + editingInvoiceBanner + }; + localStorage.setItem(draftKey, JSON.stringify(draftData)); + setDraftStatus('saved'); + setDraftSavedAt(new Date()); + } catch (e) { + console.error('Draft auto-save error:', e); + } + }, 300); + return () => clearTimeout(timer); + }, [cart, returnCart, selectedPatient, patientType, doctorName, doctorRegNo, walkinAbhaId, walkinAbhaAddress, wholeDiscountType, wholeDiscountVal, paymentMode, splitCash, splitUpi, splitCard, draftKey, editingInvoiceBanner]); + const clearDraftAndReset = () => { + try { + localStorage.removeItem(draftKey); + } catch (e) {} + setCart([]); + setReturnCart([]); + resetPatient(); + setLoadedDraft(null); + setDoctorName(''); + setDoctorRegNo(''); + setWholeDiscountVal(0); + setEditingInvoiceBanner(null); + if (onClearEditInvoice) onClearEditInvoice(); + setIsRestoredBannerVisible(false); + setDraftStatus('idle'); + notify('Draft cleared. Counter reset to new blank bill.', 'info'); + }; + + // Automatically preload latest completed sale for this store so "Last Bill" is immediately available + useEffect(() => { + if (store && store.store_id && !lastInvoice) { + fetch(API_BASE + `sales/recent?store_id=${store.store_id}&limit=1`).then(r => r.json()).then(d => { + if (d.status && d.sales && d.sales.length > 0) { + const latestSaleId = d.sales[0].sale_id; + fetch(API_BASE + `sales/invoice/${latestSaleId}`).then(ir => ir.json()).then(id => { + if (id.status) setLastInvoice(id); + }).catch(() => {}); + } + }).catch(() => {}); + } + }, [store?.store_id]); + + // B2C Sales Return & Same-Invoice Exchange State + const [returnCart, setReturnCart] = useState([]); + const [showReturnModal, setShowReturnModal] = useState(false); + const [returnSearchQuery, setReturnSearchQuery] = useState(''); + const [returnSearchResults, setReturnSearchResults] = useState([]); + const [isSearchingReturn, setIsSearchingReturn] = useState(false); + const [selectedReturnInvoice, setSelectedReturnInvoice] = useState(null); + const [returnDraftItems, setReturnDraftItems] = useState({}); + const [refundMode, setRefundMode] = useState('Cash'); // 'Cash', 'UPI' + const [refundRefNo, setRefundRefNo] = useState(''); + const returnSearchInputRef = useRef(null); + const openReturnModal = () => { + setShowReturnModal(true); + setTimeout(() => { + if (returnSearchInputRef.current) { + returnSearchInputRef.current.focus(); + returnSearchInputRef.current.select(); + } + }, 120); + }; + const searchReturnInvoices = async (query = returnSearchQuery) => { + if (!query || query.trim().length < 2) { + notify('Please enter at least 2 characters to search bills.', 'error'); + return; + } + setIsSearchingReturn(true); + setSelectedReturnInvoice(null); + try { + const res = await fetch(API_BASE + `returns/lookup-invoice?store_id=${store.store_id}&q=${encodeURIComponent(query.trim())}`); + const data = await res.json(); + if (data.status) { + setReturnSearchResults(data.results || []); + if (data.results && data.results.length === 1) { + selectReturnInvoice(data.results[0]); + } else if (!data.results || data.results.length === 0) { + notify('No invoices found matching "' + query.trim() + '"', 'error'); + } + } else { + notify(data.message || 'Error looking up invoices', 'error'); + } + } catch (e) { + notify('Invoice search error: ' + e.message, 'error'); + } finally { + setIsSearchingReturn(false); + } + }; + const selectReturnInvoice = resObj => { + setSelectedReturnInvoice(resObj); + const drafts = {}; + if (resObj && resObj.items) { + resObj.items.forEach(it => { + if (it.remaining_units > 0) { + drafts[it.sale_item_id] = { + return_qty: 0, + return_unit: it.units_per_pack > 1 && it.remaining_strips > 0 ? 'Strip' : 'Tab', + condition: 'GOOD', + reason: 'EXCESS_UNUSED' + }; + } + }); + } + setReturnDraftItems(drafts); + }; + const updateReturnDraft = (saleItemId, field, val) => { + setReturnDraftItems(prev => ({ + ...prev, + [saleItemId]: { + ...prev[saleItemId], + [field]: val + } + })); + }; + const addSelectedReturnsToBill = () => { + if (!selectedReturnInvoice) return; + const newReturns = []; + let hasAnyQty = false; + selectedReturnInvoice.items.forEach(it => { + const draft = returnDraftItems[it.sale_item_id]; + if (draft && Number(draft.return_qty) > 0) { + hasAnyQty = true; + const qty = Number(draft.return_qty); + const upp = Number(it.units_per_pack) || 1; + const totalUnits = draft.return_unit === 'Strip' ? qty * upp : qty; + if (totalUnits > it.remaining_units) { + notify(`Cannot return more than available (${it.remaining_units} tabs) for ${it.item_name}!`, 'error'); + return; + } + const lineTotal = Number((totalUnits * it.effective_unit_price).toFixed(2)); + const itemData = { + ref_sale_item_id: it.sale_item_id, + ref_sale_id: selectedReturnInvoice.sale.sale_id, + ref_invoice_no: selectedReturnInvoice.sale.invoice_no, + item_id: it.item_id, + item_name: it.item_name, + generic_name: it.generic_name, + batch_id: it.batch_id, + batch_no: it.batch_no, + expiry_date: it.expiry_date, + units_per_pack: upp, + return_qty: qty, + return_unit: draft.return_unit, + return_total_units: totalUnits, + unit_price: it.effective_unit_price, + unit_mrp: it.unit_mrp, + gst_rate: it.gst_rate, + condition: draft.condition || 'GOOD', + reason: draft.reason || 'EXCESS_UNUSED', + line_total: lineTotal + }; + const existingIdx = returnCart.findIndex(rc => rc.ref_sale_item_id === it.sale_item_id); + if (existingIdx >= 0) { + returnCart[existingIdx] = itemData; + } else { + newReturns.push(itemData); + } + } + }); + if (!hasAnyQty) { + notify('Please enter quantity > 0 for at least one item to return.', 'error'); + return; + } + setReturnCart([...returnCart, ...newReturns]); + + // If patient context is currently blank, copy patient from original invoice + if (!selectedPatient && selectedReturnInvoice.sale) { + const s = selectedReturnInvoice.sale; + if (s.patient_name || s.uhid) { + setPatientQuery(s.patient_name + (s.uhid ? ` (${s.uhid})` : '')); + if (s.doctor_name) setDoctorName(s.doctor_name); + } + } + setShowReturnModal(false); + notify('Added return medicines to current invoice! Adjustments reflected in totals.', 'success'); + }; + + // Keyboard Navigation & Focus Refs + const medicineSearchRef = useRef(null); + const patientSearchRef = useRef(null); + const wholeDiscountRef = useRef(null); + const [selectedBatchIndex, setSelectedBatchIndex] = useState(0); + const [selectedPatientIndex, setSelectedPatientIndex] = useState(0); + + // Flatten non-expired available batches for keyboard arrow navigation + const selectableBatches = []; + itemResults.forEach(it => { + if (it.batches && it.batches.length > 0) { + it.batches.forEach(b => { + if (!b.is_expired && Number(b.current_qty) > 0) { + selectableBatches.push({ + item: it, + batch: b + }); + } + }); + } + }); + useEffect(() => { + setSelectedBatchIndex(0); + }, [itemResults]); + useEffect(() => { + setSelectedPatientIndex(0); + }, [patientResults]); + const focusMedicineSearch = () => { + if (medicineSearchRef.current) { + medicineSearchRef.current.focus(); + medicineSearchRef.current.select(); + } + }; + + // Auto-focus on initial mount + useEffect(() => { + const timer = setTimeout(() => { + focusMedicineSearch(); + }, 150); + return () => clearTimeout(timer); + }, []); + + // Search patient + const searchPatients = async val => { + setPatientQuery(val); + if (val.length < 2) { + setPatientResults([]); + return; + } + try { + const res = await fetch(API_BASE + `patient/search?q=${encodeURIComponent(val)}`); + const data = await res.json(); + if (data.status) { + setPatientResults(data.patients || []); + } + } catch (e) { + console.error(e); + } + }; + const handlePatientSearchKeyDown = e => { + if (patientResults.length > 0) { + if (e.key === 'ArrowDown') { + e.preventDefault(); + setSelectedPatientIndex(prev => (prev + 1) % patientResults.length); + return; + } + if (e.key === 'ArrowUp') { + e.preventDefault(); + setSelectedPatientIndex(prev => (prev - 1 + patientResults.length) % patientResults.length); + return; + } + if (e.key === 'Enter') { + e.preventDefault(); + const chosen = patientResults[selectedPatientIndex >= 0 && selectedPatientIndex < patientResults.length ? selectedPatientIndex : 0]; + if (chosen) { + selectPatient(chosen); + setTimeout(() => focusMedicineSearch(), 50); + } + return; + } + if (e.key === 'Escape') { + e.preventDefault(); + setPatientResults([]); + return; + } + } else if (e.key === 'Enter') { + e.preventDefault(); + focusMedicineSearch(); + } + }; + const handleMedicineSearchKeyDown = e => { + if (itemResults.length > 0 && selectableBatches.length > 0) { + if (e.key === 'ArrowDown') { + e.preventDefault(); + setSelectedBatchIndex(prev => (prev + 1) % selectableBatches.length); + return; + } + if (e.key === 'ArrowUp') { + e.preventDefault(); + setSelectedBatchIndex(prev => (prev - 1 + selectableBatches.length) % selectableBatches.length); + return; + } + if (e.key === 'Enter') { + e.preventDefault(); + const chosen = selectableBatches[selectedBatchIndex >= 0 && selectedBatchIndex < selectableBatches.length ? selectedBatchIndex : 0]; + if (chosen) { + addItemToCart(chosen.item, chosen.batch, 1); + } + return; + } + if (e.key === 'Escape') { + e.preventDefault(); + setItemResults([]); + setItemQuery(''); + return; + } + } else if (e.key === 'Enter') { + e.preventDefault(); + if (itemResults.length === 1 && itemResults[0].fefo_batch) { + addItemToCart(itemResults[0], itemResults[0].fefo_batch, 1); + } + } + }; + const selectPatient = pt => { + setSelectedPatient(pt); + setPatientResults([]); + setPatientQuery(pt.full_name + ' (' + pt.uhid + ')'); + setWalkinAbhaId(pt.abha_id || ''); + setWalkinAbhaAddress(pt.abha_address || ''); + setWalkinMobile(pt.mobile || ''); + setWalkinUhid(pt.uhid || ''); + if (pt.has_active_ipd && pt.active_ipd) { + setPatientType('IPD'); + setDoctorName(pt.active_ipd.doctor_name || ''); + setPrintFormat('a4'); // Default IPD bills to A4 + } else if (pt.has_active_opd && pt.active_opd) { + setPatientType('OPD'); + setDoctorName(pt.active_opd.doctor_name || ''); + setPrintFormat('a5'); // Default OPD bills to A5 + } else { + setPatientType('Walk-in'); + setPrintFormat('thermal'); // Default walkin to Thermal + } + + // Fetch patient pharmacy history & old records on the right side + fetchPatientHistory(pt.patient_id, pt.uhid, pt.mobile); + setShowHistoryPanel(true); + }; + const resetPatient = () => { + setSelectedPatient(null); + setPatientHistory(null); + setPatientQuery(''); + setPatientType('Walk-in'); + setDoctorName(''); + setDoctorRegNo(''); + setWalkinAbhaId(''); + setWalkinAbhaAddress(''); + setWalkinMobile(''); + setWalkinUhid(''); + setPrintFormat('thermal'); + }; + const viewAbdmBundle = async saleId => { + setIsLoadingFhir(true); + setShowFhirModal(true); + setCopiedFhir(false); + try { + const res = await fetch(API_BASE + `abdm/bundle/${saleId}`); + const data = await res.json(); + if (data.status) { + setFhirBundleData(data); + } else { + notify(data.message || 'Unable to retrieve ABDM FHIR bundle', 'error'); + setShowFhirModal(false); + } + } catch (e) { + notify('FHIR Fetch error: ' + e.message, 'error'); + setShowFhirModal(false); + } finally { + setIsLoadingFhir(false); + } + }; + const copyFhirToClipboard = () => { + if (!fhirBundleData?.bundle) return; + navigator.clipboard.writeText(JSON.stringify(fhirBundleData.bundle, null, 2)); + setCopiedFhir(true); + setTimeout(() => setCopiedFhir(false), 2500); + }; + + // 1-Click Load Doctor Rx + const loadDoctorPrescription = async () => { + if (!selectedPatient) return; + const encType = selectedPatient.has_active_ipd ? 'ipd' : selectedPatient.has_active_opd ? 'opd' : null; + const encId = selectedPatient.has_active_ipd ? selectedPatient.active_ipd.ipd_id : selectedPatient.has_active_opd ? selectedPatient.active_opd.opd_id : null; + if (!encType || !encId) { + notify('No active OPD or IPD prescription found for this patient.', 'error'); + return; + } + try { + const res = await fetch(API_BASE + `patient/prescription/${encType}/${encId}`); + const data = await res.json(); + if (data.status && data.medicines && data.medicines.length > 0) { + let addedCount = 0; + for (const med of data.medicines) { + const sRes = await fetch(API_BASE + `items/search?store_id=${store.store_id}&q=${encodeURIComponent(med.medicine_name)}`); + const sData = await sRes.json(); + if (sData.status && sData.items && sData.items.length > 0) { + const matchedItem = sData.items[0]; + if (matchedItem.fefo_batch) { + addItemToCart(matchedItem, matchedItem.fefo_batch, med.prescribed_qty || 10); + addedCount++; + } + } + } + notify(`Imported ${addedCount} prescribed medicines into cart!`, 'success'); + } else { + notify('No electronic medicines found for this visit.', 'error'); + } + } catch (e) { + notify('Failed to load prescription: ' + e.message, 'error'); + } + }; + + // Search Items in Store + const searchItems = async val => { + setItemQuery(val); + if (val.length < 2) { + setItemResults([]); + return; + } + setIsSearchingItems(true); + try { + const res = await fetch(API_BASE + `items/search?store_id=${store.store_id}&q=${encodeURIComponent(val)}`); + const data = await res.json(); + if (data.status) { + setItemResults(data.items || []); + } + } catch (e) { + console.error(e); + } finally { + setIsSearchingItems(false); + } + }; + const getItemLineInfo = it => { + const upp = Number(it.units_per_pack) > 0 ? Number(it.units_per_pack) : 1; + const stripMrp = Number(it.unit_mrp) || 0; + const perUnitMrp = upp > 0 ? stripMrp / upp : stripMrp; + const sellUnit = it.sell_unit || (upp > 1 ? 'Strip' : 'Unit'); + let totalUnits = 0; + let lineGross = 0; + let unitLabel = ''; + if (upp <= 1) { + totalUnits = Math.max(1, Number(it.qty) || 1); + lineGross = totalUnits * stripMrp; + unitLabel = it.unit_pack || 'Unit'; + } else if (sellUnit === 'Tablet' || sellUnit === 'Unit') { + totalUnits = Math.max(1, Number(it.loose_qty ?? it.qty) || 1); + lineGross = totalUnits * perUnitMrp; + unitLabel = 'Tablet'; + } else if (sellUnit === 'Combo') { + const sq = Math.max(0, Number(it.strip_qty) || 0); + const lq = Math.max(0, Number(it.loose_qty) || 0); + totalUnits = sq * upp + lq; + if (totalUnits <= 0) totalUnits = 1; + lineGross = sq * stripMrp + lq * perUnitMrp; + unitLabel = 'Combo'; + } else { + // 'Strip' + const sq = Math.max(1, Number(it.strip_qty ?? it.qty) || 1); + totalUnits = sq * upp; + lineGross = sq * stripMrp; + unitLabel = 'Strip'; + } + lineGross = Number(lineGross.toFixed(2)); + const effectiveUnitPrice = sellUnit === 'Tablet' || sellUnit === 'Unit' ? Number(perUnitMrp.toFixed(2)) : stripMrp; + return { + upp, + stripMrp, + perUnitMrp: Number(perUnitMrp.toFixed(2)), + sellUnit, + totalUnits, + lineGross, + unitLabel, + effectiveUnitPrice + }; + }; + const addItemToCart = (item, batch, qty = 1) => { + if (!batch) { + notify('No active batch available for ' + item.item_name, 'error'); + return; + } + if (batch.is_expired) { + notify(`STATUTORY BLOCK: Batch ${batch.batch_no} is expired! Cannot be sold.`, 'error'); + return; + } + const upp = Number(item.units_per_pack) > 0 ? Number(item.units_per_pack) : 1; + const existingIdx = cart.findIndex(c => c.item_id === item.item_id && c.batch_id === batch.batch_id); + const targetIdx = existingIdx >= 0 ? existingIdx : cart.length; + if (existingIdx >= 0) { + const updated = [...cart]; + if (updated[existingIdx].sell_unit === 'Tablet') { + updated[existingIdx].loose_qty = (Number(updated[existingIdx].loose_qty) || 0) + qty; + updated[existingIdx].qty = updated[existingIdx].loose_qty; + } else { + updated[existingIdx].strip_qty = (Number(updated[existingIdx].strip_qty) || 0) + qty; + updated[existingIdx].qty = updated[existingIdx].strip_qty; + } + setCart(updated); + } else { + setCart([...cart, { + item_id: item.item_id, + item_name: item.item_name, + generic_name: item.generic_name, + unit_pack: item.unit_pack, + units_per_pack: upp, + drug_schedule: item.drug_schedule, + hsn_code: item.hsn_code || '3004', + gst_rate: batch.gst_rate || 12.0, + batch_id: batch.batch_id, + batch_no: batch.batch_no, + expiry_display: batch.expiry_display, + expiry_date: batch.expiry_date, + current_qty: batch.current_qty, + unit_mrp: batch.mrp, + sell_unit: upp > 1 ? 'Tablet' : 'Unit', + strip_qty: 0, + loose_qty: qty, + discount_type: 'pct', + discount_val: 0, + qty: qty + }]); + } + setItemResults([]); + setItemQuery(''); + setSelectedBatchIndex(0); + + // Auto-suggest format based on item count + if (cart.length + 1 > 5 && printFormat === 'thermal') { + setPrintFormat('a5'); + } + + // Auto-focus quantity input of the newly added/updated cart line (default to loose) + setTimeout(() => { + const row = existingIdx >= 0 ? cart[existingIdx] : null; + const sellUnit = row ? row.sell_unit : upp > 1 ? 'Tablet' : 'Unit'; + let el = null; + if (sellUnit === 'Strip') { + el = document.getElementById(`cart-qty-strip-${targetIdx}`); + } else { + el = document.getElementById(`cart-qty-loose-${targetIdx}`) || document.getElementById(`cart-qty-strip-${targetIdx}`); + } + if (el) { + el.focus(); + el.select(); + } + }, 50); + }; + const getItemDiscount = it => { + const info = getItemLineInfo(it); + const lineGross = info.lineGross; + const val = Number(it.discount_val) || 0; + if (val <= 0) return 0; + if (it.discount_type === 'val') { + return Math.min(lineGross, val); + } else { + const pct = Math.min(100, Math.max(0, val)); + return Number((lineGross * pct / 100).toFixed(2)); + } + }; + const toggleItemDiscType = idx => { + const updated = [...cart]; + const it = updated[idx]; + const info = getItemLineInfo(it); + const lineGross = info.lineGross; + const currentDisc = getItemDiscount(it); + if (it.discount_type === 'val') { + it.discount_type = 'pct'; + it.discount_val = lineGross > 0 ? Number((currentDisc / lineGross * 100).toFixed(1)) : 0; + } else { + it.discount_type = 'val'; + it.discount_val = Math.round(currentDisc); + } + setCart(updated); + }; + const switchSellUnit = (idx, newUnit) => { + const updated = [...cart]; + const it = updated[idx]; + const upp = it.units_per_pack || 1; + it.sell_unit = newUnit; + if (newUnit === 'Tablet') { + if (!it.loose_qty || Number(it.loose_qty) <= 0) { + it.loose_qty = Number(it.strip_qty) > 0 ? Number(it.strip_qty) * upp : it.qty || 1; + } + it.qty = it.loose_qty; + setCart(updated); + setTimeout(() => { + const el = document.getElementById(`cart-qty-loose-${idx}`); + if (el) { + el.focus(); + el.select(); + } + }, 30); + } else if (newUnit === 'Strip') { + if (!it.strip_qty || Number(it.strip_qty) <= 0) { + it.strip_qty = Number(it.loose_qty) > 0 ? Math.max(1, Math.round(Number(it.loose_qty) / upp)) : 1; + } + it.qty = it.strip_qty; + setCart(updated); + setTimeout(() => { + const el = document.getElementById(`cart-qty-strip-${idx}`); + if (el) { + el.focus(); + el.select(); + } + }, 30); + } else if (newUnit === 'Combo') { + if (it.strip_qty === undefined || Number(it.strip_qty) <= 0) it.strip_qty = 1; + if (it.loose_qty === undefined) it.loose_qty = 0; + setCart(updated); + setTimeout(() => { + const el = document.getElementById(`cart-qty-strip-${idx}`); + if (el) { + el.focus(); + el.select(); + } + }, 30); + } + }; + const updateCartItem = (idx, field, val) => { + const updated = [...cart]; + updated[idx][field] = val; + setCart(updated); + }; + const removeCartItem = idx => { + setCart(cart.filter((_, i) => i !== idx)); + }; + const fetchPatientHistory = async (patientId, uhid, mobile) => { + if (!patientId && !uhid && !mobile) { + setPatientHistory(null); + return; + } + setIsLoadingHistory(true); + try { + const p = new URLSearchParams(); + if (patientId) p.append('patient_id', patientId); + if (uhid) p.append('uhid', uhid); + if (mobile) p.append('mobile', mobile); + if (store?.store_id) p.append('store_id', store.store_id); + const res = await fetch(API_BASE + `patient/history?${p.toString()}`); + const data = await res.json(); + if (data.status) { + setPatientHistory(data); + if (data.invoices && data.invoices.length > 0) { + setExpandedBillId(data.invoices[0].sale.sale_id); + } + } else { + setPatientHistory(null); + } + } catch (e) { + console.error('Error fetching patient history:', e); + setPatientHistory(null); + } finally { + setIsLoadingHistory(false); + } + }; + const reDispenseMedicine = async (itemObj, defaultQty = 1) => { + try { + const searchTerm = itemObj.item_name || itemObj.med_name; + if (!searchTerm) return; + notify(`Finding current stock for "${searchTerm}"...`, 'info'); + const res = await fetch(API_BASE + `items/search?store_id=${store.store_id}&q=${encodeURIComponent(searchTerm)}`); + const data = await res.json(); + if (data.status && data.items && data.items.length > 0) { + let matched = null; + if (itemObj.item_id) { + matched = data.items.find(it => Number(it.item_id) === Number(itemObj.item_id)); + } + if (!matched) matched = data.items[0]; + if (matched && matched.fefo_batch) { + const qtyToAdd = defaultQty || (itemObj.qty ? Number(itemObj.qty) : 1); + addItemToCart(matched, matched.fefo_batch, qtyToAdd); + notify(`Added "${matched.item_name}" (Batch ${matched.fefo_batch.batch_no}) to cart!`, 'success'); + } else if (matched) { + notify(`"${matched.item_name}" is currently OUT OF STOCK in this counter!`, 'error'); + } + } else { + notify(`Medicine "${searchTerm}" not found in current inventory.`, 'error'); + } + } catch (e) { + notify('Failed to add medicine: ' + e.message, 'error'); + } + }; + const initiateReturnFromHistory = (saleObj, itemObj) => { + if (!saleObj || !itemObj) return; + const inv = patientHistory?.invoices?.find(inv => Number(inv.sale.sale_id) === Number(saleObj.sale_id)); + if (inv) { + selectReturnInvoice(inv); + const upp = Number(itemObj.units_per_pack) || 1; + const defUnit = upp > 1 && itemObj.remaining_strips > 0 ? 'Strip' : 'Tab'; + const defQty = defUnit === 'Strip' ? Math.max(1, itemObj.remaining_strips) : Math.max(1, itemObj.remaining_units); + setReturnDraftItems(prev => ({ + ...prev, + [itemObj.sale_item_id]: { + return_qty: defQty, + return_unit: defUnit, + condition: 'GOOD', + reason: 'EXCESS_UNUSED' + } + })); + openReturnModal(); + notify(`Loaded bill ${saleObj.invoice_no} for return of ${itemObj.item_name}`, 'info'); + } else { + setReturnSearchQuery(saleObj.invoice_no); + searchReturnInvoices(saleObj.invoice_no); + openReturnModal(); + } + }; + const viewPastBill = saleId => { + fetch(API_BASE + `sales/invoice/${saleId}`).then(r => r.json()).then(data => { + if (data.status) { + setLastInvoice(data); + setIsPrintOpen(true); + } else { + notify('Unable to load invoice', 'error'); + } + }).catch(err => notify('Error loading bill: ' + err.message, 'error')); + }; + + // Calculate totals with whole bill discount and return items + const grossTotal = cart.reduce((acc, it) => acc + getItemLineInfo(it).lineGross, 0); + const itemDiscountTotal = cart.reduce((acc, it) => acc + getItemDiscount(it), 0); + const balanceAfterItemDisc = Math.max(0, grossTotal - itemDiscountTotal); + let wholeDiscountAmt = 0; + const numWholeDisc = Number(wholeDiscountVal) || 0; + if (numWholeDisc > 0) { + if (wholeDiscountType === 'val') { + wholeDiscountAmt = Math.min(balanceAfterItemDisc, numWholeDisc); + } else { + const pct = Math.min(100, Math.max(0, numWholeDisc)); + wholeDiscountAmt = balanceAfterItemDisc * pct / 100; + } + } + const discountTotal = itemDiscountTotal + wholeDiscountAmt; + const netSalesBeforeReturn = Math.max(0, grossTotal - discountTotal); + const returnTotal = returnCart.reduce((acc, it) => acc + (Number(it.line_total) || 0), 0); + const netDifference = netSalesBeforeReturn - returnTotal; + let netPayable = 0; + let refundPayable = 0; + let roundOff = '0.00'; + if (netDifference >= 0) { + netPayable = Math.round(netDifference); + roundOff = (netPayable - netDifference).toFixed(2); + refundPayable = 0; + } else { + refundPayable = Math.round(Math.abs(netDifference)); + roundOff = (refundPayable - Math.abs(netDifference)).toFixed(2); + netPayable = 0; + } + const splitCashNum = Number(splitCash) || 0; + const splitUpiNum = Number(splitUpi) || 0; + const splitCardNum = Number(splitCard) || 0; + const totalSplitAllocated = splitCashNum + splitUpiNum + splitCardNum; + const splitRemaining = Number((netPayable - totalSplitAllocated).toFixed(2)); + + // Save and print sale or return/exchange bill + const processSale = async () => { + if (cart.length === 0 && returnCart.length === 0) { + notify('Cart has no items to bill or return!', 'error'); + return; + } + if (paymentMode === 'Staff_Credit' && !selectedCreditAccount) { + notify('Please select a Staff / Customer credit account to bill.', 'error'); + return; + } + if (paymentMode === 'IPD_Credit' && (!selectedPatient || !selectedPatient.has_active_ipd)) { + notify('IPD Credit mode is only allowed for admitted IPD patients.', 'error'); + return; + } + let finalCash = 0; + let finalUpi = 0; + let finalCard = 0; + let finalCredit = 0; + if (refundPayable > 0) { + // Patient receives a refund; no positive payment collected + } else { + if (paymentMode === 'Cash') { + finalCash = netPayable; + } else if (paymentMode === 'UPI') { + finalUpi = netPayable; + } else if (paymentMode === 'Card') { + finalCard = netPayable; + } else if (paymentMode === 'IPD_Credit') { + finalCredit = netPayable; + } else if (paymentMode === 'Staff_Credit') { + finalCredit = netPayable; + } else if (paymentMode === 'Mixed') { + finalCash = splitCashNum; + finalUpi = splitUpiNum; + finalCard = splitCardNum; + if (Math.abs(splitRemaining) > 0.01) { + notify(`Split payment total (₹${totalSplitAllocated.toFixed(2)}) does not match Net Payable (₹${netPayable})! Difference: ₹${splitRemaining.toFixed(2)}`, 'error'); + return; + } + } + } + setIsProcessing(true); + const payload = { + store_id: store.store_id, + draft_id: loadedDraft ? loadedDraft.draft_id : null, + draft_code: loadedDraft ? loadedDraft.draft_code : null, + patient_type: patientType, + uhid: selectedPatient ? selectedPatient.uhid : walkinUhid || null, + patient_id: selectedPatient ? selectedPatient.patient_id : null, + opd_id: selectedPatient && selectedPatient.active_opd ? selectedPatient.active_opd.opd_id : null, + ipd_id: selectedPatient && selectedPatient.active_ipd ? selectedPatient.active_ipd.ipd_id : null, + patient_name: selectedPatient ? selectedPatient.full_name : patientQuery || 'Walk-in Customer', + patient_mobile: selectedPatient ? selectedPatient.mobile : walkinMobile || '', + patient_address: selectedPatient ? selectedPatient.address : '', + abha_id: selectedPatient?.abha_id || walkinAbhaId || null, + abha_address: selectedPatient?.abha_address || walkinAbhaAddress || null, + age: selectedPatient ? selectedPatient.age : '', + gender: selectedPatient ? selectedPatient.gender : '', + doctor_name: doctorName || selectedPatient?.active_opd?.doctor_name || selectedPatient?.active_ipd?.doctor_name || 'Dr. Consultant', + doctor_reg_no: doctorRegNo, + payment_mode: refundPayable > 0 ? refundMode === 'Cash' ? 'Cash' : 'UPI' : paymentMode, + credit_account_id: paymentMode === 'Staff_Credit' && selectedCreditAccount ? selectedCreditAccount.account_id : null, + credit_person_name: paymentMode === 'Staff_Credit' && selectedCreditAccount ? selectedCreditAccount.account_name : null, + cash_paid: finalCash, + upi_paid: finalUpi, + card_paid: finalCard, + credit_amount: finalCredit, + refund_amount: refundPayable, + refund_mode: refundPayable > 0 ? refundMode : '', + refund_ref_no: refundPayable > 0 ? refundRefNo : '', + payment_reference: paymentRef || upiRefNo || cardRefNo, + bank_name: bankName, + upi_ref_no: upiRefNo, + card_ref_no: cardRefNo, + whole_discount_type: wholeDiscountType, + whole_discount_val: Number(wholeDiscountVal) || 0, + biller_name: activeOperator?.full_name || 'Store Staff', + operator_name: activeOperator?.full_name || 'Store Staff', + user_id: activeOperator?.user_id || 1, + items: cart.map(it => { + const info = getItemLineInfo(it); + const lineGross = info.lineGross; + const lineDisc = getItemDiscount(it); + const discPct = lineGross > 0 ? Number((lineDisc / lineGross * 100).toFixed(2)) : 0; + return { + item_id: it.item_id, + batch_id: it.batch_id, + qty: Number(it.qty) || 1, + sell_unit: info.sellUnit, + units_per_pack: info.upp, + strip_qty: Number(it.strip_qty) || 0, + loose_qty: Number(it.loose_qty) || 0, + total_units: info.totalUnits, + effective_rate: info.effectiveUnitPrice, + line_gross: lineGross, + discount_type: it.discount_type || 'pct', + discount_val: Number(it.discount_val) || 0, + discount_pct: discPct, + discount_amount: lineDisc + }; + }), + return_items: returnCart.map(rc => ({ + ref_sale_item_id: rc.ref_sale_item_id, + ref_sale_id: rc.ref_sale_id, + ref_invoice_no: rc.ref_invoice_no, + item_id: rc.item_id, + batch_id: rc.batch_id, + return_qty: rc.return_qty, + return_unit: rc.return_unit, + units_per_pack: rc.units_per_pack, + return_total_units: rc.return_total_units, + unit_price: rc.unit_price, + return_amount: rc.line_total, + condition: rc.condition || 'GOOD', + reason: rc.reason || 'EXCESS_UNUSED' + })) + }; + try { + const res = await fetch(API_BASE + 'sales/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const data = await res.json(); + if (data.status) { + const msg = data.refund_amount > 0 ? `Return Bill ${data.invoice_no} processed! Refund: ₹${data.refund_amount} (${data.refund_mode})` : `Invoice ${data.invoice_no} generated successfully! Net Amount: ₹${data.net_amount}`; + notify(msg, 'success'); + fetchInvoiceDetails(data.sale_id); + setIsCheckoutOpen(false); + setCart([]); + setReturnCart([]); + setWholeDiscountVal(0); + setSplitCash(''); + setSplitUpi(''); + setSplitCard(''); + setUpiRefNo(''); + setBankName(''); + setCardRefNo(''); + setPaymentRef(''); + resetPatient(); + setLoadedDraft(null); + loadDraftBills('DRAFT'); + try { + localStorage.removeItem(draftKey); + } catch (e) {} + setDraftStatus('idle'); + setEditingInvoiceBanner(null); + if (onClearEditInvoice) onClearEditInvoice(); + } else { + notify(data.message || 'Failed to complete transaction.', 'error'); + } + } catch (e) { + notify('Sale error: ' + e.message, 'error'); + } finally { + setIsProcessing(false); + } + }; + const fetchInvoiceDetails = async saleId => { + try { + const res = await fetch(API_BASE + `sales/invoice/${saleId}`); + const data = await res.json(); + if (data.status) { + setLastInvoice(data); + setIsPrintOpen(true); + } + } catch (e) { + console.error(e); + } + }; + const generateThermalReceiptText = inv => { + if (!inv || !inv.sale) return ''; + const sale = inv.sale; + const items = inv.items || []; + const returnItems = inv.return_items || []; + const LINE_WIDTH = 48; // Standard 80mm thermal receipt line length (Font A: 48 chars) + + const center = str => { + str = (str || '').trim(); + if (str.length >= LINE_WIDTH) return str.substring(0, LINE_WIDTH); + const pad = Math.floor((LINE_WIDTH - str.length) / 2); + return ' '.repeat(pad) + str; + }; + const padLine = (left, right) => { + left = left || ''; + right = right || ''; + const space = LINE_WIDTH - left.length - right.length; + if (space <= 0) return left + ' ' + right; + return left + ' '.repeat(space) + right; + }; + const divider = '='.repeat(LINE_WIDTH); + const dashDivider = '-'.repeat(LINE_WIDTH); + let lines = []; + lines.push(divider); + lines.push(center(sale.store_name || 'HOSPITAL PHARMACY')); + if (sale.building_name || sale.floor_no) { + lines.push(center(`${sale.building_name || ''}, ${sale.floor_no || ''}`)); + } + if (sale.store_address) { + lines.push(center(sale.store_address)); + } + if (sale.contact_phone) { + lines.push(center(`Phone: ${sale.contact_phone}`)); + } + if (sale.drug_license_no_20b || sale.drug_license_no_21b) { + lines.push(center(`DL 20B: ${sale.drug_license_no_20b || 'N/A'} | 21B: ${sale.drug_license_no_21b || 'N/A'}`)); + } + if (sale.gstin) { + lines.push(center(`GSTIN: ${sale.gstin}${sale.state_code ? ` (State: ${sale.state_code})` : ''}`)); + } + if (sale.fssai_no) { + lines.push(center(`FSSAI: ${sale.fssai_no}`)); + } + if (sale.abdm_hfr_id) { + lines.push(center(`HFR ID: ${sale.abdm_hfr_id}`)); + } + lines.push(divider); + lines.push(center('RETAIL TAX INVOICE')); + lines.push(padLine(`Bill No: ${sale.invoice_no}`, `Date: ${sale.sale_date ? sale.sale_date.substring(0, 16) : ''}`)); + lines.push(padLine(`Patient: ${sale.patient_name || 'Walk-in'}`, `UHID: ${sale.uhid || 'Walk-in'}`)); + if (sale.patient_mobile) { + lines.push(padLine(`Mobile : ${sale.patient_mobile}`, `Age/Sex: ${sale.age || 'N/A'}/${sale.gender || 'N/A'}`)); + } + if (sale.doctor_name) { + lines.push(`Doctor : ${sale.doctor_name}`); + } + if (sale.abha_id || sale.abha_address) { + lines.push(`ABHA : ${sale.abha_id || ''} ${sale.abha_address ? `(${sale.abha_address})` : ''}`); + } + if (sale.abdm_care_context_ref) { + lines.push(`ABDM Ref: ${sale.abdm_care_context_ref}`); + } + if (sale.ipd_id) { + lines.push(`IPD # : ${sale.ipd_id} (Ward: ${sale.ward_name || ''} Bed: ${sale.bed_no || ''})`); + } + lines.push(dashDivider); + + // Header: Item (22), Batch (9), Qty (7), Total (10) + lines.push('Item'.padEnd(22) + 'Batch'.padEnd(9) + 'Qty'.padStart(7) + 'Total'.padStart(10)); + lines.push(dashDivider); + if (items.length === 0) { + lines.push(center('- Return / Refund Only -')); + } else { + items.forEach(it => { + const name = (it.item_name || '').substring(0, 21).padEnd(22); + const batch = (it.batch_no || '').substring(0, 8).padEnd(9); + const qtyStr = (it.sell_unit === 'Tablet' ? `${it.total_units}T` : it.sell_unit === 'Combo' ? `${it.qty}S+${it.loose_qty}T` : `${it.qty}`).substring(0, 6).padStart(7); + const amtStr = Number(it.total_amount || 0).toFixed(2).padStart(10); + lines.push(name + batch + qtyStr + amtStr); + let sub = ` Exp:${(it.expiry_date || '').substring(0, 7)} HSN:${it.hsn_code || '3004'} GST:${it.gst_rate}%`; + if (it.sell_unit === 'Tablet') { + sub += ` @Rs.${it.unit_price}/tab`; + } else { + sub += ` @Rs.${it.unit_mrp}`; + } + lines.push(sub.substring(0, LINE_WIDTH)); + }); + } + if (returnItems.length > 0) { + lines.push(dashDivider); + lines.push(center('-- RETURNED / EXCHANGED --')); + if (inv.credit_note) { + lines.push(center(`Credit Note: ${inv.credit_note.credit_note_no}`)); + } + returnItems.forEach(it => { + const name = ('*' + (it.item_name || '')).substring(0, 21).padEnd(22); + const batch = (it.batch_no || '').substring(0, 8).padEnd(9); + const qtyStr = ('-' + (it.sell_unit === 'Tablet' ? `${it.total_units}T` : `${it.qty}`)).substring(0, 6).padStart(7); + const amtStr = ('-' + Math.abs(Number(it.total_amount || 0)).toFixed(2)).padStart(10); + lines.push(name + batch + qtyStr + amtStr); + }); + } + lines.push(dashDivider); + lines.push(padLine('Gross Total:', `Rs. ${Number(sale.gross_amount || 0).toFixed(2)}`)); + if (Number(sale.discount_amount) > 0) { + lines.push(padLine('Discounts Allowed:', `-Rs. ${Number(sale.discount_amount).toFixed(2)}`)); + } + if (Number(sale.return_amount) > 0) { + lines.push(padLine('Less Return Credit:', `-Rs. ${Number(sale.return_amount).toFixed(2)}`)); + } + lines.push(padLine('Taxable Amount:', `Rs. ${Number(sale.taxable_amount || 0).toFixed(2)}`)); + lines.push(padLine('CGST Amount:', `Rs. ${Number(sale.cgst_amount || 0).toFixed(2)}`)); + lines.push(padLine('SGST Amount:', `Rs. ${Number(sale.sgst_amount || 0).toFixed(2)}`)); + if (Number(sale.round_off) !== 0) { + lines.push(padLine('Round Off:', `Rs. ${Number(sale.round_off || 0).toFixed(2)}`)); + } + lines.push(divider); + lines.push(padLine('NET PAYABLE:', `Rs. ${Number(sale.net_amount || 0).toFixed(2)}`)); + lines.push(divider); + if (Number(sale.refund_amount) > 0) { + lines.push(padLine('REFUND PAID:', `Rs. ${Number(sale.refund_amount).toFixed(2)}`)); + lines.push(padLine('Refund Mode:', `${sale.refund_mode} ${sale.refund_ref_no || ''}`)); + lines.push(dashDivider); + } + lines.push(`Settlement: ${sale.payment_mode}`); + if (Number(sale.cash_paid) > 0) lines.push(` Cash Paid : Rs. ${Number(sale.cash_paid).toFixed(2)}`); + if (Number(sale.upi_paid) > 0) lines.push(` UPI/Bank : Rs. ${Number(sale.upi_paid).toFixed(2)} ${sale.upi_ref_no ? `[UTR:${sale.upi_ref_no}]` : ''}`); + if (Number(sale.card_paid) > 0) lines.push(` Card Paid : Rs. ${Number(sale.card_paid).toFixed(2)} ${sale.card_ref_no ? `[Ref:${sale.card_ref_no}]` : ''}`); + if (Number(sale.credit_amount) > 0) lines.push(` IPD Credit: Rs. ${Number(sale.credit_amount).toFixed(2)}`); + if (sale.is_bank_reconciled == 1) lines.push(' Status : Bank Statement Audited');else lines.push(' Status : Bank Statement Pending Audit'); + lines.push(dashDivider); + if (sale.registered_pharmacist_name) { + lines.push(`R.Ph: ${sale.registered_pharmacist_name} (${sale.pharmacist_reg_no || 'N/A'})`); + } + lines.push(center(sale.terms_conditions || 'Thank you! Get well soon.')); + lines.push(divider); + return lines.join('\n'); + }; + const copyThermalReceiptText = () => { + if (!lastInvoice) return; + const txt = generateThermalReceiptText(lastInvoice); + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(txt).then(() => { + notify('Thermal receipt text copied to clipboard!', 'success'); + }).catch(() => { + fallbackCopyText(txt); + }); + } else { + fallbackCopyText(txt); + } + }; + const fallbackCopyText = txt => { + const ta = document.createElement('textarea'); + ta.value = txt; + ta.style.position = 'fixed'; + ta.style.left = '-9999px'; + document.body.appendChild(ta); + ta.select(); + try { + document.execCommand('copy'); + notify('Thermal receipt text copied to clipboard!', 'success'); + } catch (err) { + notify('Unable to copy text.', 'error'); + } + document.body.removeChild(ta); + }; + const printThermalReceipt = () => { + if (!lastInvoice) return; + const txt = generateThermalReceiptText(lastInvoice); + const win = window.open('', '_blank', 'width=420,height=650'); + if (!win) { + notify('Pop-up blocked. Please allow pop-ups to print thermal receipt.', 'warning'); + return; + } + try { + win.document.title = 'Thermal Receipt - ' + (lastInvoice.sale ? lastInvoice.sale.invoice_no : ''); + const style = win.document.createElement('style'); + style.textContent = '@page { size: 80mm auto; margin: 0; } html, body { margin: 0; padding: 0; background: #fff; } body { padding: 4mm 2mm; font-family: Courier, monospace; font-size: 11px; line-height: 1.25; color: #000; } pre { margin: 0; font-family: inherit; font-size: inherit; white-space: pre-wrap; word-break: break-all; }'; + win.document.head.appendChild(style); + const pre = win.document.createElement('pre'); + pre.textContent = txt; + win.document.body.appendChild(pre); + setTimeout(() => { + try { + win.focus(); + win.print(); + setTimeout(() => { + try { + win.close(); + } catch (err) {} + }, 1000); + } catch (err) {} + }, 250); + } catch (e) { + console.error('Print thermal error:', e); + } + }; + const printPdf = format => { + if (!lastInvoice || !lastInvoice.sale) return; + const saleId = lastInvoice.sale.sale_id; + const url = `/api/v1/medical-store/sales/invoice-pdf/${saleId}?format=${format || 'a4'}`; + let iframe = document.getElementById('pdf-print-iframe'); + if (!iframe) { + iframe = document.createElement('iframe'); + iframe.id = 'pdf-print-iframe'; + iframe.style.position = 'fixed'; + iframe.style.right = '0'; + iframe.style.bottom = '0'; + iframe.style.width = '0'; + iframe.style.height = '0'; + iframe.style.border = '0'; + document.body.appendChild(iframe); + } + iframe.src = url; + iframe.onload = function () { + try { + iframe.contentWindow.focus(); + iframe.contentWindow.print(); + } catch (e) { + window.open(url, '_blank'); + } + }; + }; + const downloadPdf = format => { + if (!lastInvoice || !lastInvoice.sale) return; + const saleId = lastInvoice.sale.sale_id; + window.open(`/api/v1/medical-store/sales/invoice-pdf/${saleId}?format=${format || 'a4'}&download=1`, '_blank'); + }; + + // Global Keyboard Shortcuts (Desktop Pharmacy Standard) + useEffect(() => { + const handleGlobalKeyDown = e => { + // Dismiss Modals or Drawers on Escape + if (showFhirModal || showReturnModal || isCheckoutOpen || isPrintOpen) { + if (e.key === 'Escape') { + e.preventDefault(); + if (showFhirModal) setShowFhirModal(false);else if (showReturnModal) setShowReturnModal(false);else if (isCheckoutOpen) setIsCheckoutOpen(false);else if (isPrintOpen) setIsPrintOpen(false); + } + return; + } + + // F2: Jump to Medicine Search / Barcode scanner + if (e.key === 'F2') { + e.preventDefault(); + focusMedicineSearch(); + return; + } + + // F4: Jump to Patient Search + if (e.key === 'F4') { + e.preventDefault(); + if (patientSearchRef.current) { + patientSearchRef.current.focus(); + patientSearchRef.current.select(); + } + return; + } + + // F6 or Alt+R: Jump to Sales Return & Same-Invoice Exchange Desk + if (e.key === 'F6' || e.altKey && (e.key === 'r' || e.key === 'R')) { + e.preventDefault(); + openReturnModal(); + return; + } + + // F7: Jump to Whole Bill Discount (opens Checkout Drawer if closed) + if (e.key === 'F7') { + e.preventDefault(); + setIsCheckoutOpen(true); + setTimeout(() => { + if (wholeDiscountRef.current) { + wholeDiscountRef.current.focus(); + wholeDiscountRef.current.select(); + } + }, 150); + return; + } + + // F8: Open Checkout Drawer or Cycle Payment Mode + if (e.key === 'F8') { + e.preventDefault(); + if (!isCheckoutOpen) { + setIsCheckoutOpen(true); + } else { + const modes = ['Cash', 'UPI', 'Card', 'Mixed']; + if (selectedPatient?.has_active_ipd) modes.push('IPD_Credit'); + const curIdx = modes.indexOf(paymentMode); + const nextMode = modes[(curIdx + 1) % modes.length]; + setPaymentMode(nextMode); + } + return; + } + + // F9 or Ctrl+Enter or Alt+S: Open Checkout or Complete Sale & Print Bill + if (e.key === 'F9' || e.ctrlKey && e.key === 'Enter' || e.altKey && (e.key === 's' || e.key === 'S')) { + e.preventDefault(); + if (!isCheckoutOpen) { + setIsCheckoutOpen(true); + } else { + if (!isProcessing && (cart.length > 0 || returnCart.length > 0)) { + processSale(); + } + } + return; + } + }; + window.addEventListener('keydown', handleGlobalKeyDown); + return () => window.removeEventListener('keydown', handleGlobalKeyDown); + }, [showFhirModal, showReturnModal, isCheckoutOpen, isPrintOpen, paymentMode, selectedPatient, isProcessing, cart, returnCart, splitRemaining, splitCashNum, splitUpiNum, splitCardNum, refundPayable, refundMode]); + return /*#__PURE__*/_jsxs("div", { + className: "pos-counter-wrapper position-relative", + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3", + children: [/*#__PURE__*/_jsxs("div", { + className: selectedPatient && showHistoryPanel ? "col-12 col-lg-8 col-xl-8" : "col-12", + children: [isRestoredBannerVisible && /*#__PURE__*/_jsxs("div", { + className: "alert alert-info py-2 px-3 d-flex flex-wrap justify-content-between align-items-center mb-2 shadow-sm border-info rounded-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise text-info fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("strong", { + className: "text-dark", + children: "Draft Auto-Restored:" + }), /*#__PURE__*/_jsxs("span", { + className: "text-secondary ms-1", + children: ["Recovered ", /*#__PURE__*/_jsxs("strong", { + children: [cart.length, " medicine(s)"] + }), " ", selectedPatient ? /*#__PURE__*/_jsxs(_Fragment, { + children: ["for ", /*#__PURE__*/_jsx("strong", { + children: selectedPatient.name || selectedPatient.patient_name + })] + }) : '', " from your previous session ", draftSavedAt ? `(${draftSavedAt.toLocaleTimeString()})` : '', "."] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2 mt-1 mt-md-0", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-primary py-0.5 px-2.5", + onClick: () => setIsRestoredBannerVisible(false), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-lg me-1" + }), " Continue Working"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-danger py-0.5 px-2.5", + onClick: clearDraftAndReset, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-trash me-1" + }), " Discard Draft"] + })] + })] + }), editingInvoiceBanner && /*#__PURE__*/_jsxs("div", { + className: "alert alert-warning py-2 px-3 d-flex flex-wrap justify-content-between align-items-center mb-2 shadow-sm border-warning rounded-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square text-warning-emphasis fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: ["Editing Invoice #", editingInvoiceBanner, ":"] + }), /*#__PURE__*/_jsx("span", { + className: "text-secondary ms-1", + children: "Patient and medicines loaded into POS Counter. You can adjust items, quantities, or re-dispense." + })] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-dark py-0.5 px-2.5 mt-1 mt-md-0", + onClick: clearDraftAndReset, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " Cancel Edit & New Bill"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "counter-card position-relative", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark fs-6", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-fill text-primary me-1" + }), " Patient & Prescription"] + }), /*#__PURE__*/_jsx("span", { + className: `badge ${patientType === 'IPD' ? 'bg-danger' : patientType === 'OPD' ? 'bg-primary' : 'bg-secondary'}`, + children: patientType + }), draftStatus === 'saved' && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success-subtle px-2 py-0.5 d-inline-flex align-items-center gap-1 shadow-sm", + style: { + fontSize: '0.72rem' + }, + title: draftSavedAt ? `Auto-saved at ${draftSavedAt.toLocaleTimeString()}` : 'Auto-saved in local draft', + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cloud-check-fill" + }), " Draft Auto-Saved (", cart.length, " items)"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1.5 flex-wrap", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm ${draftBillsList.length > 0 ? 'btn-warning text-dark fw-bold' : 'btn-outline-secondary'} py-0.5 px-2.5 d-inline-flex align-items-center gap-1 shadow-sm`, + onClick: () => { + loadDraftBills(); + setShowDraftModal(true); + }, + title: "Draft bills collected from racks via Mobile App", + style: { + fontSize: "0.75rem" + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone" + }), /*#__PURE__*/_jsx("span", { + children: "Mobile Drafts" + }), draftBillsList.length > 0 && /*#__PURE__*/_jsx("span", { + className: "badge bg-danger text-white rounded-pill ms-1", + style: { + fontSize: '0.65rem' + }, + children: draftBillsList.length + })] + }), (cart.length > 0 || selectedPatient) && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-0.5 px-2 d-inline-flex align-items-center gap-1 shadow-sm", + onClick: clearDraftAndReset, + title: "Discard draft and start new blank bill", + style: { + fontSize: "0.75rem" + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle" + }), " New Bill"] + }), lastInvoice && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-success py-0.5 px-2.5 fw-semibold d-inline-flex align-items-center gap-1 shadow-sm", + onClick: () => setIsPrintOpen(true), + title: "View & Print Last Bill", + style: { + fontSize: "0.75rem" + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer" + }), " Last Bill: ", /*#__PURE__*/_jsx("strong", { + children: lastInvoice.sale.invoice_no + })] + })] + }), selectedPatient && /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1.5 flex-wrap", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm ${showHistoryPanel ? 'btn-primary text-white' : 'btn-outline-primary'} py-1 px-2.5 d-inline-flex align-items-center gap-1 shadow-sm`, + onClick: () => setShowHistoryPanel(!showHistoryPanel), + title: "Toggle Patient Old Records & Past Dispensed Medicines (Right-Side)", + style: { + fontSize: "0.75rem" + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history" + }), /*#__PURE__*/_jsx("span", { + children: "Old Records" + }), patientHistory && patientHistory.total_sales > 0 && /*#__PURE__*/_jsx("span", { + className: `badge ${showHistoryPanel ? 'bg-white text-primary' : 'bg-primary text-white'} ms-1`, + style: { + fontSize: "0.65rem" + }, + children: patientHistory.total_sales + })] + }), (selectedPatient.has_active_opd || selectedPatient.has_active_ipd) && /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-success py-1 px-2.5", + onClick: loadDoctorPrescription, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-medical me-1" + }), " 1-Click Load Doctor Rx"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-secondary py-1 px-2", + onClick: resetPatient, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " Clear"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-7 position-relative", + children: [/*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsxs("span", { + className: "input-group-text bg-light text-primary fw-bold", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + className: "me-1", + style: { + background: '#0f172a', + color: '#38bdf8', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px' + }, + children: "F4" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + id: "patient-search-input", + ref: patientSearchRef, + className: "form-control", + placeholder: "Search by UHID, Mobile, Name, OPD No, IPD No... (F4)", + value: patientQuery, + onChange: e => searchPatients(e.target.value), + onKeyDown: handlePatientSearchKeyDown, + autoComplete: "off" + })] + }), patientResults.length > 0 && /*#__PURE__*/_jsx("div", { + className: "search-results-dropdown", + children: patientResults.map((p, pIdx) => { + const isHighlighted = pIdx === selectedPatientIndex; + return /*#__PURE__*/_jsxs("div", { + className: `search-item-row d-flex justify-content-between align-items-center ${isHighlighted ? 'bg-primary-subtle border-primary' : ''}`, + onClick: () => { + selectPatient(p); + setTimeout(() => focusMedicineSearch(), 50); + }, + style: { + cursor: 'pointer' + }, + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark", + children: [p.full_name, " ", /*#__PURE__*/_jsxs("small", { + className: "text-primary", + children: ["(", p.uhid, ")"] + }), isHighlighted && /*#__PURE__*/_jsx("span", { + className: "badge bg-primary text-white ms-2", + style: { + fontSize: '0.65rem' + }, + children: "↵ Enter" + }), (p.abha_id || p.abha_address) && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success ms-2", + style: { + fontSize: '0.65rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check me-1" + }), "ABHA: ", p.abha_id || p.abha_address] + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-1" + }), p.mobile || 'No Mobile', " • ", p.gender, " • ", p.age] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [p.has_active_ipd && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger d-block mb-1", + children: ["IPD Admitted: ", p.active_ipd.bed_info?.bed_no || 'Bed'] + }), p.has_active_opd && /*#__PURE__*/_jsx("span", { + className: "badge bg-info d-block", + children: "OPD Visit Today" + })] + })] + }, p.patient_id); + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "col-md-5", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "Consultant Doctor Name", + value: doctorName, + onChange: e => setDoctorName(e.target.value) + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mt-1", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-6", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsxs("span", { + className: "input-group-text bg-light text-success fw-bold", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " ABHA No"] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "14-Digit ABHA (e.g. 12-3456-7890-1234)", + value: walkinAbhaId, + onChange: e => setWalkinAbhaId(e.target.value) + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-6", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsxs("span", { + className: "input-group-text bg-light text-success fw-bold", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-at me-1" + }), " ABHA Address"] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "username@abdm", + value: walkinAbhaAddress, + onChange: e => setWalkinAbhaAddress(e.target.value) + })] + }) + })] + }), selectedPatient && /*#__PURE__*/_jsxs("div", { + className: "mt-2 p-2 bg-light rounded-2 d-flex flex-wrap gap-3 align-items-center", + style: { + fontSize: '0.8rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Name:" + }), " ", selectedPatient.full_name] + }), /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "UHID:" + }), " ", /*#__PURE__*/_jsx("code", { + className: "text-primary", + children: selectedPatient.uhid + })] + }), /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Gender/Age:" + }), " ", selectedPatient.gender, ", ", selectedPatient.age] + }), (selectedPatient.abha_id || selectedPatient.abha_address) && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success text-white py-1 px-2", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check me-1" + }), " ABDM Linked: ", selectedPatient.abha_id || '', " ", selectedPatient.abha_address ? `(${selectedPatient.abha_address})` : ''] + }), selectedPatient.has_active_ipd && /*#__PURE__*/_jsxs("span", { + className: "text-danger fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital me-1" + }), selectedPatient.active_ipd.bed_info?.ward_name || 'Ward', " / ", selectedPatient.active_ipd.bed_info?.bed_no || 'Bed', " (Dr. ", selectedPatient.active_ipd.doctor_name, ")"] + }), selectedPatient.has_active_opd && !selectedPatient.has_active_ipd && /*#__PURE__*/_jsxs("span", { + className: "text-primary fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-stethoscope me-1" + }), "OPD Dr. ", selectedPatient.active_opd.doctor_name] + })] + }), !selectedPatient && (walkinMobile || walkinUhid) && /*#__PURE__*/_jsxs("div", { + className: "mt-2 p-2 bg-light rounded-2 d-flex flex-wrap gap-3 align-items-center", + style: { + fontSize: '0.8rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Customer:" + }), " ", patientQuery || 'Walk-in'] + }), walkinMobile && /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Mobile:" + }), " ", /*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-1 text-primary" + }), walkinMobile] + }), walkinUhid && /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "UHID:" + }), " ", /*#__PURE__*/_jsx("code", { + className: "text-primary", + children: walkinUhid + })] + })] + }), loadedDraft && /*#__PURE__*/_jsxs("div", { + className: "mt-2 p-2 rounded-2 d-flex flex-wrap justify-content-between align-items-center gap-2", + style: { + background: '#fef3c7', + border: '1px solid #f59e0b', + fontSize: '0.8rem' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-warning text-dark fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone me-1" + }), " Draft: ", loadedDraft.draft_code] + }), /*#__PURE__*/_jsxs("span", { + className: "text-dark", + children: ["Collector: ", /*#__PURE__*/_jsx("strong", { + children: loadedDraft.collected_by_name || 'Staff' + }), loadedDraft.ward_name ? ` • Ward: ${loadedDraft.ward_name} (${loadedDraft.bed_no || ''})` : ''] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-secondary border", + style: { + fontSize: '0.7rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-right-circle me-1 text-success" + }), "Auto-converts to invoice on checkout"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-dark py-0 px-2", + onClick: () => { + setLoadedDraft(null); + notify(`Draft [${loadedDraft.draft_code}] unlinked. Cart items kept.`, 'info'); + }, + title: "Unlink this draft without clearing the cart", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-link-45deg me-1" + }), " Unlink Draft"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "counter-card position-relative", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center gap-1.5 mb-2.5 py-1.5 px-2.5 rounded-3 shadow-sm", + style: { + background: '#f8fafc', + border: '1px solid #cbd5e1' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold d-flex align-items-center me-1", + style: { + color: '#0f172a', + fontSize: '0.74rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-keyboard-fill text-primary me-1 fs-6" + }), /*#__PURE__*/_jsx("span", { + children: "Keys:" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#38bdf8', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "F2" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Search" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#38bdf8', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "↑ / ↓" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Select" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#38bdf8', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "↵ Enter" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Batch" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border border-primary shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0891b2', + color: '#ffffff', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "↵ on Qty" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold text-primary", + children: "Next Item" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#10b981', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "Alt+T" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Loose" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#38bdf8', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "Alt+S" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Strip" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#f59e0b', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "F4" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Patient" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2 py-0.5 bg-white rounded border shadow-xs", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#0f172a', + color: '#a855f7', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "F8" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + style: { + color: '#0f172a' + }, + children: "Payment" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs py-0.5 px-2 bg-white rounded border border-danger shadow-xs d-inline-flex align-items-center gap-1", + onClick: openReturnModal, + style: { + fontSize: '0.72rem' + }, + title: "Accept patient returns or exchange on current bill (Alt+R / F6)", + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#e11d48', + color: '#ffffff', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "Alt+R / F6" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold text-danger", + children: "Return / Exch" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "d-inline-flex align-items-center gap-1 px-2.5 py-0.5 rounded text-white shadow-sm", + style: { + background: '#059669', + fontSize: '0.72rem', + border: '1px solid #047857' + }, + children: [/*#__PURE__*/_jsx("kbd", { + style: { + background: '#ffffff', + color: '#065f46', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px', + fontSize: '0.68rem' + }, + children: "F9 / Ctrl+↵" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + children: "Bill & Print" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2 mb-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-upc-scan text-primary fs-5" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold fs-6", + children: "Medicine Lookup & Barcode Dispenser" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group", + children: [/*#__PURE__*/_jsxs("span", { + className: "input-group-text bg-light text-primary fw-bold", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("kbd", { + className: "me-1", + style: { + background: '#0f172a', + color: '#38bdf8', + fontWeight: 800, + padding: '1px 5px', + borderRadius: '3px' + }, + children: "F2" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-capsule" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + id: "item-search-input", + ref: medicineSearchRef, + className: "form-control fw-semibold", + placeholder: "Type Medicine Name, Generic Molecule, or Scan Box Barcode... (Press F2 anytime)", + value: itemQuery, + onChange: e => searchItems(e.target.value), + onKeyDown: handleMedicineSearchKeyDown, + autoComplete: "off" + }), isSearchingItems && /*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split" + }) + })] + }), itemResults.length > 0 && /*#__PURE__*/_jsx("div", { + className: "search-results-dropdown", + children: itemResults.map(it => /*#__PURE__*/_jsxs("div", { + className: "search-item-row", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "fw-bold text-dark fs-6", + children: it.item_name + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary ms-2", + style: { + fontSize: '0.65rem' + }, + children: it.unit_pack + }), it.drug_schedule && it.drug_schedule !== 'OTC' && /*#__PURE__*/_jsx("span", { + className: "badge bg-warning-subtle text-warning border border-warning ms-1", + style: { + fontSize: '0.65rem' + }, + children: it.drug_schedule + })] + }), /*#__PURE__*/_jsx("div", { + children: /*#__PURE__*/_jsxs("span", { + className: "text-muted me-2", + style: { + fontSize: '0.75rem' + }, + children: ["Total Stock: ", it.total_stock] + }) + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block mb-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-diagram-3 me-1" + }), it.generic_name, " • HSN: ", it.hsn_code] + }), it.batches && it.batches.length > 0 ? /*#__PURE__*/_jsx("div", { + className: "d-flex flex-wrap gap-2 mt-1", + children: it.batches.map(b => { + const isHighlighted = selectableBatches[selectedBatchIndex] && selectableBatches[selectedBatchIndex].batch.batch_id === b.batch_id && selectableBatches[selectedBatchIndex].item.item_id === it.item_id; + return /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${isHighlighted ? 'btn-warning text-dark border-2 shadow-sm fw-bold' : b.is_expired ? 'btn-outline-danger disabled' : 'btn-outline-dark'} d-flex align-items-center gap-1 py-0.5 px-2`, + style: { + fontSize: '0.75rem', + transform: isHighlighted ? 'scale(1.04)' : 'scale(1)', + transition: 'transform 0.1s' + }, + onClick: () => addItemToCart(it, b, 1), + disabled: b.is_expired, + title: isHighlighted ? 'Press Enter to select this batch' : `Select batch ${b.batch_no}`, + children: [/*#__PURE__*/_jsx("strong", { + children: b.batch_no + }), /*#__PURE__*/_jsxs("span", { + children: ["(Exp: ", b.expiry_display, ")"] + }), /*#__PURE__*/_jsxs("span", { + className: "text-success fw-bold", + children: ["₹", b.mrp] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary text-white", + children: [b.current_qty, " left"] + }), it.fefo_batch && it.fefo_batch.batch_id === b.batch_id && /*#__PURE__*/_jsx("span", { + className: "badge-fefo ms-1", + children: "FEFO" + }), b.is_near_expiry && /*#__PURE__*/_jsx("span", { + className: "badge-near-expiry ms-1", + children: "Near Exp" + }), b.is_expired && /*#__PURE__*/_jsx("span", { + className: "badge-expired ms-1", + children: "EXPIRED" + }), isHighlighted && /*#__PURE__*/_jsx("span", { + className: "badge bg-dark text-warning ms-1", + style: { + fontSize: '0.62rem' + }, + children: "↵ Enter" + })] + }, b.batch_id); + }) + }) : /*#__PURE__*/_jsx("span", { + className: "text-danger fw-bold", + style: { + fontSize: '0.75rem' + }, + children: "Out of Stock in this Counter" + })] + }, it.item_id)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "counter-card p-0 overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "p-3 pb-2 d-flex flex-wrap justify-content-between align-items-center gap-2 border-bottom", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("h6", { + className: "mb-0 fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-check-fill text-success me-1" + }), " Dispensing Cart (", cart.length, " new)"] + }), returnCart.length > 0 && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), returnCart.length, " return/exchange"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2 align-items-center", + children: [(cart.length > 0 || returnCart.length > 0) && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-success py-0.5 px-2.5 fw-bold d-inline-flex align-items-center gap-1.5 shadow-sm", + onClick: () => setIsCheckoutOpen(true), + style: { + fontSize: '0.75rem', + background: '#10b981', + borderColor: '#059669' + }, + title: "Open Checkout Desk to finalize bill (F8 / F9)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-wallet2" + }), " Checkout ", refundPayable > 0 ? `(Refund ₹${refundPayable})` : `(₹${netPayable})`, " ", /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-right" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-danger py-0.5 px-2.5 fw-semibold d-inline-flex align-items-center gap-1", + onClick: openReturnModal, + style: { + fontSize: '0.75rem' + }, + title: "Add patient return or item exchange (Alt+R / F6)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left" + }), " Add Return / Exch"] + }), (cart.length > 0 || returnCart.length > 0) && /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-link text-muted text-decoration-none p-0", + onClick: () => { + setCart([]); + setReturnCart([]); + }, + children: "Clear All" + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + style: { + maxHeight: 380 + }, + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Name" + }), /*#__PURE__*/_jsx("th", { + children: "Batch / Exp" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 155 + }, + children: "Qty & Unit" + }), /*#__PURE__*/_jsx("th", { + children: "Rate (₹)" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 125 + }, + children: "Disc (% / ₹)" + }), /*#__PURE__*/_jsx("th", { + children: "GST%" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Total (₹)" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 40 + } + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: cart.length === 0 && returnCart.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "9", + className: "text-center py-4 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-basket3 fs-3 d-block mb-1" + }), "Scan barcode or search medicine to add items, or click ", /*#__PURE__*/_jsx("strong", { + className: "text-danger", + children: "Add Return / Exch" + }), " (Alt+R / F6)."] + }) + }) : cart.map((it, idx) => { + const info = getItemLineInfo(it); + const lineGross = info.lineGross; + const lineDisc = getItemDiscount(it); + const lineNet = Math.max(0, lineGross - lineDisc).toFixed(2); + const upp = info.upp; + return /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: idx + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold", + children: it.item_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [it.generic_name, " • HSN: ", it.hsn_code] + }), upp > 1 && /*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary-subtle text-secondary border ms-1", + style: { + fontSize: '0.62rem' + }, + children: ["Pack: ", it.unit_pack || `${upp} Tabs`] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border", + children: it.batch_no + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.7rem' + }, + children: ["Exp: ", it.expiry_display] + })] + }), /*#__PURE__*/_jsx("td", { + children: upp > 1 ? /*#__PURE__*/_jsxs("div", { + style: { + maxWidth: 155 + }, + children: [it.sell_unit === 'Combo' ? /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm py-0 px-1 fw-bold bg-warning-subtle text-dark border-warning", + style: { + maxWidth: 64, + fontSize: '0.72rem' + }, + value: it.sell_unit, + onChange: e => switchSellUnit(idx, e.target.value), + title: "Unit Type: Combo (Strips + Loose Tablets)", + children: [/*#__PURE__*/_jsx("option", { + value: "Tablet", + children: "Tab" + }), /*#__PURE__*/_jsx("option", { + value: "Strip", + children: "Strip" + }), /*#__PURE__*/_jsx("option", { + value: "Combo", + children: "Str+Tab" + })] + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: `cart-qty-strip-${idx}`, + className: "form-control form-control-sm text-center fw-bold px-1", + min: "0", + placeholder: "Str", + title: "Whole Strips", + value: it.strip_qty ?? 1, + onChange: e => updateCartItem(idx, 'strip_qty', Number(e.target.value)), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + focusMedicineSearch(); + } else if (e.key === 'Delete' && e.shiftKey) { + e.preventDefault(); + removeCartItem(idx); + focusMedicineSearch(); + } + } + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: `cart-qty-loose-${idx}`, + className: "form-control form-control-sm text-center fw-bold text-success border-success px-1", + min: "0", + placeholder: "Tab", + title: "Loose Tablets", + value: it.loose_qty ?? 0, + onChange: e => updateCartItem(idx, 'loose_qty', Number(e.target.value)), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + focusMedicineSearch(); + } else if (e.key === 'Delete' && e.shiftKey) { + e.preventDefault(); + removeCartItem(idx); + focusMedicineSearch(); + } + } + })] + }) : /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsxs("select", { + className: `form-select form-select-sm py-0 px-1 fw-bold ${it.sell_unit === 'Strip' ? 'bg-primary-subtle text-primary border-primary' : 'bg-success-subtle text-success border-success'}`, + style: { + maxWidth: 65, + fontSize: '0.72rem' + }, + value: it.sell_unit || 'Tablet', + onChange: e => switchSellUnit(idx, e.target.value), + title: "Select Unit Type before quantity", + children: [/*#__PURE__*/_jsx("option", { + value: "Tablet", + children: "Tab" + }), /*#__PURE__*/_jsx("option", { + value: "Strip", + children: "Strip" + }), /*#__PURE__*/_jsx("option", { + value: "Combo", + children: "Str+Tab" + })] + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: it.sell_unit === 'Strip' ? `cart-qty-strip-${idx}` : `cart-qty-loose-${idx}`, + className: `form-control form-control-sm text-center fw-bold ${it.sell_unit === 'Strip' ? 'text-primary' : 'text-success border-success'}`, + min: "1", + max: it.current_qty, + value: it.sell_unit === 'Strip' ? it.strip_qty ?? it.qty ?? 1 : it.loose_qty ?? it.qty ?? 1, + onChange: e => { + const val = Number(e.target.value); + const updated = [...cart]; + if (it.sell_unit === 'Strip') { + updated[idx].strip_qty = val; + } else { + updated[idx].loose_qty = val; + } + updated[idx].qty = val; + setCart(updated); + }, + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + focusMedicineSearch(); + } else if (e.altKey && (e.key === 's' || e.key === 'S')) { + e.preventDefault(); + switchSellUnit(idx, 'Strip'); + } else if (e.altKey && (e.key === 't' || e.key === 'T')) { + e.preventDefault(); + switchSellUnit(idx, 'Tablet'); + } else if (e.altKey && (e.key === 'c' || e.key === 'C')) { + e.preventDefault(); + switchSellUnit(idx, 'Combo'); + } else if (e.key === 'Delete' && e.shiftKey) { + e.preventDefault(); + removeCartItem(idx); + focusMedicineSearch(); + } + } + })] + }), /*#__PURE__*/_jsx("div", { + className: "text-muted text-center mt-0.5", + style: { + fontSize: '0.64rem' + }, + children: it.sell_unit === 'Tablet' ? `= ${info.totalUnits} Tab (₹${info.perUnitMrp}/tab)` : it.sell_unit === 'Combo' ? `= ${info.totalUnits} Tab total` : `= ${info.totalUnits} Tab (${upp}/str)` + })] + }) : /*#__PURE__*/_jsxs("div", { + style: { + maxWidth: 120 + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light text-muted px-1.5 py-0 fw-semibold", + style: { + fontSize: '0.68rem', + maxWidth: 50 + }, + children: it.unit_pack || 'Unit' + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: `cart-qty-strip-${idx}`, + className: "form-control form-control-sm text-center fw-bold", + min: "1", + max: it.current_qty, + value: it.qty, + onChange: e => updateCartItem(idx, 'qty', Number(e.target.value)), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + focusMedicineSearch(); + } else if (e.key === 'Delete' && e.shiftKey) { + e.preventDefault(); + removeCartItem(idx); + focusMedicineSearch(); + } + } + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted text-center mt-0.5", + style: { + fontSize: '0.64rem' + }, + children: ["₹", it.unit_mrp, " each"] + })] + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold", + children: it.sell_unit === 'Tablet' ? /*#__PURE__*/_jsxs("span", { + children: ["₹", info.perUnitMrp, " ", /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/tab" + })] + }) : it.sell_unit === 'Combo' ? /*#__PURE__*/_jsxs("span", { + children: ["₹", it.unit_mrp, " ", /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/str" + })] + }) : /*#__PURE__*/_jsxs("span", { + children: ["₹", it.unit_mrp, " ", upp > 1 ? /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/strip" + }) : ''] + }) + }), upp > 1 && /*#__PURE__*/_jsx("small", { + className: "text-muted d-block", + style: { + fontSize: '0.68rem' + }, + children: it.sell_unit === 'Tablet' ? `Strip: ₹${it.unit_mrp}` : `Tab: ₹${info.perUnitMrp}` + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + style: { + width: 115 + }, + children: [/*#__PURE__*/_jsx("input", { + type: "number", + id: `cart-disc-${idx}`, + className: "form-control form-control-sm text-center px-1 fw-semibold", + min: "0", + max: it.discount_type === 'pct' ? 100 : lineGross, + step: it.discount_type === 'pct' ? '0.5' : '1', + value: it.discount_val ?? '', + placeholder: "0", + onChange: e => updateCartItem(idx, 'discount_val', e.target.value), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + focusMedicineSearch(); + } + } + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `btn btn-sm ${it.discount_type === 'pct' ? 'btn-primary' : 'btn-warning text-dark'} px-2 py-0 fw-bold`, + title: `Click to switch between % and ₹ (Currently: ${it.discount_type === 'pct' ? 'Percentage' : 'Value in Rupees'})`, + onClick: () => toggleItemDiscType(idx), + children: it.discount_type === 'pct' ? '%' : '₹' + })] + }), lineDisc > 0 && /*#__PURE__*/_jsx("div", { + className: "text-muted text-center mt-0.5", + style: { + fontSize: '0.68rem' + }, + children: it.discount_type === 'pct' ? `-₹${lineDisc.toFixed(2)}` : `${lineGross > 0 ? (lineDisc / lineGross * 100).toFixed(1) : 0}% off` + })] + }), /*#__PURE__*/_jsxs("td", { + children: [it.gst_rate, "%"] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold text-dark", + children: ["₹", lineNet] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-danger py-0 px-1", + onClick: () => removeCartItem(idx), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-trash" + }) + }) + })] + }, `sale-${idx}`); + }).concat(returnCart.map((rc, rIdx) => /*#__PURE__*/_jsxs("tr", { + style: { + backgroundColor: 'rgba(244, 63, 94, 0.05)' + }, + children: [/*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-danger text-white", + children: "RET" + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-danger", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), rc.item_name] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: ["Bill: ", /*#__PURE__*/_jsx("code", { + children: rc.ref_invoice_no + }), " • ", rc.reason ? rc.reason.replace(/_/g, ' ') : 'Return'] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border", + children: rc.batch_no + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.7rem' + }, + children: ["Exp: ", rc.expiry_date ? rc.expiry_date.substring(0, 7) : ''] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger fw-bold", + children: ["- ", rc.return_qty, " ", rc.return_unit] + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted mt-0.5", + style: { + fontSize: '0.64rem' + }, + children: ["(", rc.return_total_units, " Tabs • ", rc.condition === 'GOOD' ? 'Restocking' : 'Discard', ")"] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-semibold text-danger", + children: ["₹", rc.unit_price, " ", /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/tab" + })] + }), rc.units_per_pack > 1 && /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '0.68rem' + }, + children: ["MRP: ₹", rc.unit_mrp] + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary", + style: { + fontSize: '0.7rem' + }, + children: rc.condition === 'GOOD' ? 'Restock' : 'Scrap' + }) + }), /*#__PURE__*/_jsxs("td", { + children: [rc.gst_rate || 12, "%"] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold text-danger", + children: ["-₹", Number(rc.line_total).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-danger py-0 px-1", + onClick: () => setReturnCart(returnCart.filter((_, i) => i !== rIdx)), + title: "Remove from returns", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-trash" + }) + }) + })] + }, `ret-${rIdx}`))) + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "p-3 bg-light border-top d-flex flex-wrap justify-content-between align-items-center gap-3", + children: [/*#__PURE__*/_jsx("div", { + className: "d-flex flex-wrap align-items-center gap-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary-subtle text-secondary border px-2.5 py-1.5 fw-semibold", + style: { + fontSize: '0.8rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-check me-1" + }), " ", cart.length + returnCart.length, " Line Items"] + }), /*#__PURE__*/_jsxs("span", { + className: "text-muted small", + children: ["Gross: ", /*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: ["₹", grossTotal.toFixed(2)] + })] + }), itemDiscountTotal > 0 && /*#__PURE__*/_jsxs("span", { + className: "text-muted small", + children: ["Item Disc: ", /*#__PURE__*/_jsxs("strong", { + className: "text-danger", + children: ["-₹", itemDiscountTotal.toFixed(2)] + })] + }), wholeDiscountAmt > 0 && /*#__PURE__*/_jsxs("span", { + className: "text-muted small", + children: ["Bill Disc: ", /*#__PURE__*/_jsxs("strong", { + className: "text-danger", + children: ["-₹", wholeDiscountAmt.toFixed(2)] + })] + }), returnTotal > 0 && /*#__PURE__*/_jsxs("span", { + className: "text-muted small", + children: ["Return Credit: ", /*#__PURE__*/_jsxs("strong", { + className: "text-danger", + children: ["-₹", returnTotal.toFixed(2)] + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsx("div", { + className: "text-muted small text-uppercase fw-semibold", + style: { + fontSize: '0.68rem', + letterSpacing: '0.5px' + }, + children: refundPayable > 0 ? 'Customer Refund' : 'Net Amount' + }), /*#__PURE__*/_jsxs("div", { + className: `fs-4 fw-bolder ${refundPayable > 0 ? 'text-danger' : 'text-success'}`, + style: { + lineHeight: 1.1 + }, + children: ["₹", refundPayable > 0 ? refundPayable.toFixed(2) : netPayable.toFixed(2)] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + id: "btn-pos-checkout-trigger", + className: "btn btn-success btn-lg px-4 py-2.5 fw-bold shadow d-flex align-items-center gap-2", + disabled: cart.length === 0 && returnCart.length === 0, + onClick: () => setIsCheckoutOpen(true), + style: { + background: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', + border: 'none', + borderRadius: '10px', + fontSize: '1rem', + letterSpacing: '0.3px', + transition: 'transform 0.15s ease, box-shadow 0.15s ease' + }, + title: "Open Checkout Desk to review totals, select payment method and complete sale (F8 / F9)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-wallet2 fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "Checkout" + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-white text-success ms-1 px-2 py-0.5", + style: { + fontSize: '0.72rem', + fontWeight: 800 + }, + children: "F8 / F9" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-right fs-5" + })] + })] + })] + })] + })] + }), selectedPatient && showHistoryPanel && /*#__PURE__*/_jsx("div", { + className: "col-12 col-lg-4 col-xl-4", + children: /*#__PURE__*/_jsxs("div", { + className: "patient-history-sidebar position-sticky shadow-sm", + style: { + top: '15px', + maxHeight: 'calc(100vh - 100px)', + display: 'flex', + flexDirection: 'column' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "patient-history-header", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1.5", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history text-info fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold text-white", + style: { + fontSize: '0.9rem' + }, + children: "Patient Pharmacy History" + }), /*#__PURE__*/_jsxs("small", { + className: "text-secondary", + style: { + fontSize: '0.72rem' + }, + children: ["UHID: ", /*#__PURE__*/_jsx("span", { + className: "text-warning fw-bold", + children: selectedPatient.uhid + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-light py-0.5 px-2", + onClick: () => fetchPatientHistory(selectedPatient.patient_id, selectedPatient.uhid, selectedPatient.mobile), + disabled: isLoadingHistory, + title: "Refresh Patient History", + style: { + fontSize: '0.7rem' + }, + children: /*#__PURE__*/_jsx("i", { + className: `bi bi-arrow-clockwise ${isLoadingHistory ? 'spin' : ''}` + }) + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-light py-0.5 px-2", + onClick: () => setShowHistoryPanel(false), + title: "Hide sidebar (Click 'Old Records' in patient bar to re-open)", + style: { + fontSize: '0.7rem' + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-chevron-bar-right" + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-1 pt-1.5 border-top border-secondary", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "text-light", + children: [/*#__PURE__*/_jsx("strong", { + children: selectedPatient.full_name + }), " • ", selectedPatient.gender, ", ", selectedPatient.age] + }), patientHistory && /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary px-1.5 py-0.5", + children: [patientHistory.total_sales || 0, " Bills • ₹", patientHistory.total_spend || 0] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "patient-history-tabs", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `patient-history-tab-btn ${historyActiveTab === 'last_given' ? 'active' : ''}`, + onClick: () => setHistoryActiveTab('last_given'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-capsule text-success" + }), /*#__PURE__*/_jsx("span", { + children: "Last Given" + }), patientHistory?.last_dispensed_items?.length > 0 && /*#__PURE__*/_jsx("span", { + className: "badge bg-success text-white rounded-pill px-1", + style: { + fontSize: '0.62rem' + }, + children: patientHistory.last_dispensed_items.length + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `patient-history-tab-btn ${historyActiveTab === 'all_bills' ? 'active' : ''}`, + onClick: () => setHistoryActiveTab('all_bills'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt text-primary" + }), /*#__PURE__*/_jsx("span", { + children: "Past Bills" + }), patientHistory?.invoices?.length > 0 && /*#__PURE__*/_jsx("span", { + className: "badge bg-primary text-white rounded-pill px-1", + style: { + fontSize: '0.62rem' + }, + children: patientHistory.invoices.length + })] + }), patientHistory?.doctor_prescriptions?.length > 0 && /*#__PURE__*/_jsxs("button", { + type: "button", + className: `patient-history-tab-btn ${historyActiveTab === 'prescriptions' ? 'active' : ''}`, + onClick: () => setHistoryActiveTab('prescriptions'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-stethoscope text-danger" + }), /*#__PURE__*/_jsx("span", { + children: "Doctor Rx" + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-danger text-white rounded-pill px-1", + style: { + fontSize: '0.62rem' + }, + children: patientHistory.doctor_prescriptions.length + })] + }), patientHistory?.unique_medicines?.length > 0 && /*#__PURE__*/_jsxs("button", { + type: "button", + className: `patient-history-tab-btn ${historyActiveTab === 'summary' ? 'active' : ''}`, + onClick: () => setHistoryActiveTab('summary'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-medical text-warning" + }), /*#__PURE__*/_jsx("span", { + children: "All Meds" + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary text-white rounded-pill px-1", + style: { + fontSize: '0.62rem' + }, + children: patientHistory.unique_medicines.length + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "patient-history-body", + children: isLoadingHistory ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary me-2" + }), "Loading patient records..."] + }) : !patientHistory || patientHistory.total_sales === 0 && (!patientHistory.doctor_prescriptions || patientHistory.doctor_prescriptions.length === 0) ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-4 px-2 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-folder-x fs-1 text-secondary opacity-50 d-block mb-2" + }), /*#__PURE__*/_jsx("h6", { + className: "fw-semibold text-dark", + children: "No Previous Pharmacy Records" + }), /*#__PURE__*/_jsx("small", { + children: "This patient has no recorded medicine dispenses or bills in the pharmacy database yet." + })] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [historyActiveTab === 'last_given' && /*#__PURE__*/_jsx("div", { + children: patientHistory.last_sale ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("div", { + className: "p-2.5 mb-2 rounded-3 border", + style: { + background: '#f0fdf4', + borderColor: '#bbf7d0' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-success", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-1" + }), " Last Dispensed Visit"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-dark text-white", + style: { + fontSize: '0.68rem' + }, + children: patientHistory.last_sale.invoice_no + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-event me-1" + }), " ", patientHistory.last_sale.sale_date ? patientHistory.last_sale.sale_date.substring(0, 16) : 'N/A'] + }), patientHistory.last_sale.doctor_name && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge me-1" + }), " Prescribed by: ", /*#__PURE__*/_jsx("strong", { + children: patientHistory.last_sale.doctor_name + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mt-1.5 pt-1 border-top border-success-subtle", + children: [/*#__PURE__*/_jsxs("span", { + children: ["Paid: ", /*#__PURE__*/_jsxs("strong", { + children: ["₹", patientHistory.last_sale.net_amount] + }), " (", patientHistory.last_sale.payment_mode, ")"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-success py-0 px-2 fw-bold", + onClick: () => viewPastBill(patientHistory.last_sale.sale_id), + style: { + fontSize: '0.68rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " View Bill"] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark mb-1.5 d-flex justify-content-between align-items-center", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: ["Medicines Given (", patientHistory.last_dispensed_items.length, "):"] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: ["Click ", /*#__PURE__*/_jsx("strong", { + children: "+" + }), " to re-dispense"] + })] + }), patientHistory.last_dispensed_items.map((it, mIdx) => /*#__PURE__*/_jsxs("div", { + className: "history-med-card last-given", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start mb-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + style: { + fontSize: '0.82rem' + }, + children: it.item_name + }), /*#__PURE__*/_jsx("small", { + className: "text-muted d-block", + style: { + fontSize: '0.68rem' + }, + children: it.generic_name + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark", + style: { + fontSize: '0.82rem' + }, + children: ["₹", it.total_amount] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '0.68rem' + }, + children: ["₹", it.unit_mrp, "/", it.sell_unit] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center gap-1 mb-2", + style: { + fontSize: '0.68rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border", + children: ["Batch: ", it.batch_no] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-secondary border", + children: ["Exp: ", it.expiry_date] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary text-white", + children: ["Qty: ", it.qty, " ", it.sell_unit] + }), it.remaining_units > 0 ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success", + children: ["Returnable: ", it.remaining_strips > 0 ? `${it.remaining_strips} Str ` : '', it.remaining_loose > 0 ? `${it.remaining_loose} Tab` : ''] + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-muted border", + children: "Fully Returned" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1.5 pt-1.5 border-top", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-success py-1 px-2 fw-semibold d-inline-flex align-items-center gap-1 shadow-xs flex-fill justify-content-center", + onClick: () => reDispenseMedicine(it, it.qty), + style: { + fontSize: '0.72rem', + background: '#059669', + borderColor: '#047857' + }, + title: "Add this medicine to active dispensing cart with current FEFO batch", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle-fill" + }), /*#__PURE__*/_jsx("span", { + children: "Dispense Again" + })] + }), it.remaining_units > 0 && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-danger py-1 px-2 fw-semibold d-inline-flex align-items-center gap-1 shadow-xs", + onClick: () => initiateReturnFromHistory(patientHistory.last_sale, it), + style: { + fontSize: '0.72rem' + }, + title: "Return or exchange this dispensed item into current bill", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left" + }), /*#__PURE__*/_jsx("span", { + children: "Return" + })] + })] + })] + }, `last-med-${mIdx}`))] + }) : /*#__PURE__*/_jsxs("div", { + className: "text-center py-4 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-basket text-secondary fs-3 d-block mb-1" + }), "No pharmacy sales recorded yet for this patient."] + }) + }), historyActiveTab === 'all_bills' && /*#__PURE__*/_jsx("div", { + children: patientHistory.invoices?.map((inv, invIdx) => { + const s = inv.sale; + const isExp = expandedBillId === s.sale_id; + return /*#__PURE__*/_jsxs("div", { + className: "card mb-2 border shadow-xs", + style: { + borderRadius: '8px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header py-2 px-2.5 bg-white d-flex justify-content-between align-items-center", + style: { + cursor: 'pointer', + borderBottom: isExp ? '1px solid #e2e8f0' : 'none' + }, + onClick: () => setExpandedBillId(isExp ? null : s.sale_id), + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark d-flex align-items-center gap-1.5", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: `bi bi-chevron-${isExp ? 'down' : 'right'} text-primary`, + style: { + fontSize: '0.7rem' + } + }), /*#__PURE__*/_jsx("span", { + children: s.invoice_no + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-secondary border", + style: { + fontSize: '0.65rem' + }, + children: [inv.items.length, " items"] + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + style: { + fontSize: '0.68rem' + }, + children: [s.sale_date ? s.sale_date.substring(0, 10) : '', " • Dr. ", s.doctor_name || 'Consultant'] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-success d-block", + style: { + fontSize: '0.82rem' + }, + children: ["₹", s.net_amount] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary", + style: { + fontSize: '0.62rem' + }, + children: s.payment_mode + })] + })] + }), isExp && /*#__PURE__*/_jsxs("div", { + className: "card-body p-2 bg-light", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1.5", + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted fw-semibold", + style: { + fontSize: '0.7rem' + }, + children: "Items Dispensed:" + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-dark py-0 px-1.5", + onClick: e => { + e.stopPropagation(); + viewPastBill(s.sale_id); + }, + style: { + fontSize: '0.65rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Reprint"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-danger py-0 px-1.5", + onClick: e => { + e.stopPropagation(); + selectReturnInvoice(inv); + openReturnModal(); + }, + style: { + fontSize: '0.65rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), " Return All"] + })] + })] + }), inv.items.map((it, itIdx) => /*#__PURE__*/_jsxs("div", { + className: "p-1.5 mb-1 bg-white rounded border d-flex justify-content-between align-items-center", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: it.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: ["Batch: ", it.batch_no, " • ", it.qty, " ", it.sell_unit, " @ ₹", it.unit_mrp] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-success py-0 px-1", + onClick: () => reDispenseMedicine(it, it.qty), + title: "Dispense again", + style: { + fontSize: '0.68rem' + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-plus" + }) + }), it.remaining_units > 0 && /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-danger py-0 px-1", + onClick: () => initiateReturnFromHistory(s, it), + title: "Return this item", + style: { + fontSize: '0.68rem' + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left" + }) + })] + })] + }, `inv-item-${itIdx}`))] + })] + }, `inv-${s.sale_id}`); + }) + }), historyActiveTab === 'prescriptions' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "text-muted mb-2 fw-semibold", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-stethoscope text-primary me-1" + }), " Doctor Prescriptions from OPD Visits:"] + }), patientHistory.doctor_prescriptions?.map((dp, dpIdx) => /*#__PURE__*/_jsxs("div", { + className: "history-med-card mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start mb-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + style: { + fontSize: '0.82rem' + }, + children: dp.med_name + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary border", + style: { + fontSize: '0.65rem' + }, + children: dp.med_type || 'Medicine' + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '0.68rem' + }, + children: dp.date_opd_visit + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted mb-1.5", + style: { + fontSize: '0.7rem' + }, + children: [dp.doc_name && /*#__PURE__*/_jsxs("div", { + children: ["Doc: ", /*#__PURE__*/_jsxs("strong", { + children: ["Dr. ", dp.doc_name] + })] + }), /*#__PURE__*/_jsxs("div", { + children: ["Dose: ", dp.dosage_freq_str || dp.dosage || '1 Tab', " • Duration: ", dp.no_of_days || '5 Days'] + }), dp.remark && /*#__PURE__*/_jsxs("div", { + children: ["Note: ", dp.remark] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-primary w-100 py-1 fw-semibold d-flex align-items-center justify-content-center gap-1 shadow-xs", + onClick: () => reDispenseMedicine({ + item_name: dp.med_name, + qty: 10 + }), + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle" + }), " Dispense Prescribed Medicine"] + })] + }, `doc-rx-${dpIdx}`))] + }), historyActiveTab === 'summary' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "text-muted mb-2 fw-semibold", + style: { + fontSize: '0.72rem' + }, + children: "Distinct Medicines Dispensed to Patient:" + }), patientHistory.unique_medicines?.map((um, uIdx) => /*#__PURE__*/_jsxs("div", { + className: "history-med-card mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start mb-1", + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + style: { + fontSize: '0.8rem' + }, + children: um.item_name + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border", + style: { + fontSize: '0.65rem' + }, + children: [um.times_dispensed, "x dispensed"] + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block mb-1.5", + style: { + fontSize: '0.68rem' + }, + children: ["Last on ", um.last_dispensed ? um.last_dispensed.substring(0, 10) : '', " (Batch: ", um.last_batch_no, ")"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-success w-100 py-0.5 fw-semibold d-flex align-items-center justify-content-center gap-1", + onClick: () => reDispenseMedicine(um, um.last_qty || 1), + style: { + fontSize: '0.7rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle" + }), " Dispense Again"] + })] + }, `uniq-med-${uIdx}`))] + })] + }) + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: `checkout-drawer-overlay ${isCheckoutOpen ? 'open' : ''}`, + onClick: () => setIsCheckoutOpen(false) + }), /*#__PURE__*/_jsxs("div", { + className: `checkout-drawer ${isCheckoutOpen ? 'open' : ''}`, + id: "pos-checkout-drawer", + children: [/*#__PURE__*/_jsxs("div", { + className: "checkout-drawer-header", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-coin text-warning fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold text-white", + children: "Checkout Desk" + }), /*#__PURE__*/_jsxs("small", { + className: "text-secondary", + style: { + fontSize: '0.72rem' + }, + children: ["Counter: ", /*#__PURE__*/_jsx("span", { + className: "text-info fw-bold", + children: store?.store_code || '' + }), " • ", store?.store_name] + })] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-light rounded-pill px-3 py-1 d-flex align-items-center gap-1.5", + onClick: () => setIsCheckoutOpen(false), + title: "Close Checkout Drawer (Esc)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-lg" + }), /*#__PURE__*/_jsx("span", { + children: "Close" + }), /*#__PURE__*/_jsx("kbd", { + className: "ms-1", + style: { + background: '#334155', + color: '#f8fafc', + fontSize: '0.65rem', + padding: '1px 4px', + borderRadius: '3px' + }, + children: "Esc" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "checkout-drawer-body", + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold text-white mb-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsx("span", { + children: "Checkout Desk" + }), /*#__PURE__*/_jsx("span", { + className: "fs-6 text-primary", + children: store?.store_code || '' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 mb-3", + style: { + background: 'rgba(255, 255, 255, 0.08)', + border: '1px solid rgba(255, 255, 255, 0.15)' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1.5", + children: [/*#__PURE__*/_jsxs("label", { + className: "text-white small fw-bold mb-0 d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-tag-fill text-warning" + }), " Whole Bill Discount"] + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: `btn btn-xs py-0.5 px-2 ${wholeDiscountType === 'pct' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setWholeDiscountType('pct'), + children: "% Percent" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `btn btn-xs py-0.5 px-2 ${wholeDiscountType === 'val' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setWholeDiscountType('val'), + children: "₹ Fixed Value" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm mb-2", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-dark border-secondary text-warning fw-bold", + children: wholeDiscountType === 'pct' ? '%' : '₹' + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: "whole-discount-input", + ref: wholeDiscountRef, + className: "form-control form-control-sm bg-dark text-white border-secondary fw-bold", + min: "0", + max: wholeDiscountType === 'pct' ? 100 : balanceAfterItemDisc, + step: wholeDiscountType === 'pct' ? '0.5' : '1', + placeholder: wholeDiscountType === 'pct' ? 'Enter % (F7)' : 'Enter ₹ (F7)', + value: wholeDiscountVal || '', + onChange: e => setWholeDiscountVal(e.target.value), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + if (!isProcessing && cart.length > 0) { + processSale(); + } + } + } + }), Number(wholeDiscountVal) > 0 && /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-danger", + title: "Reset Whole Bill Discount", + onClick: () => setWholeDiscountVal(0), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x-lg" + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-1 align-items-center", + children: [/*#__PURE__*/_jsx("small", { + className: "text-slate-400 me-1", + style: { + fontSize: '0.7rem', + color: '#94a3b8' + }, + children: "Presets:" + }), wholeDiscountType === 'pct' ? [5, 10, 15, 20].map(p => /*#__PURE__*/_jsxs("button", { + type: "button", + className: `badge border ${Number(wholeDiscountVal) === p ? 'bg-warning text-dark border-warning' : 'bg-transparent text-white border-secondary'}`, + style: { + cursor: 'pointer', + padding: '4px 8px', + fontSize: '0.7rem' + }, + onClick: () => setWholeDiscountVal(p), + children: [p, "%"] + }, p)) : [20, 50, 100, 200].map(v => /*#__PURE__*/_jsxs("button", { + type: "button", + className: `badge border ${Number(wholeDiscountVal) === v ? 'bg-warning text-dark border-warning' : 'bg-transparent text-white border-secondary'}`, + style: { + cursor: 'pointer', + padding: '4px 8px', + fontSize: '0.7rem' + }, + onClick: () => setWholeDiscountVal(v), + children: ["₹", v] + }, v)), Number(wholeDiscountVal) > 0 && /*#__PURE__*/_jsx("button", { + type: "button", + className: "badge bg-danger-subtle text-danger border border-danger ms-auto", + style: { + cursor: 'pointer', + padding: '4px 6px', + fontSize: '0.7rem' + }, + onClick: () => setWholeDiscountVal(0), + children: "Clear" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1.5 text-slate-300", + style: { + color: '#cbd5e1' + }, + children: [/*#__PURE__*/_jsx("span", { + children: "Gross Items Total:" + }), /*#__PURE__*/_jsxs("span", { + className: "fw-bold", + children: ["₹", grossTotal.toFixed(2)] + })] + }), itemDiscountTotal > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1 text-slate-300", + style: { + fontSize: '0.84rem', + color: '#94a3b8' + }, + children: [/*#__PURE__*/_jsx("span", { + children: "Item-Level Discounts:" + }), /*#__PURE__*/_jsxs("span", { + className: "text-danger", + children: ["-₹", itemDiscountTotal.toFixed(2)] + })] + }), wholeDiscountAmt > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1 text-slate-300", + style: { + fontSize: '0.84rem', + color: '#94a3b8' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: ["Whole Bill Discount (", wholeDiscountType === 'pct' ? `${wholeDiscountVal}%` : `₹${wholeDiscountVal}`, "):"] + }), /*#__PURE__*/_jsxs("span", { + className: "text-danger", + children: ["-₹", wholeDiscountAmt.toFixed(2)] + })] + }), discountTotal > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-2 text-slate-300", + style: { + color: '#cbd5e1' + }, + children: [/*#__PURE__*/_jsx("span", { + children: "Total Discounts:" + }), /*#__PURE__*/_jsxs("span", { + className: "text-danger fw-bold", + children: ["-₹", discountTotal.toFixed(2)] + })] + }), returnTotal > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-2 text-danger fw-bold py-1 px-2 rounded", + style: { + background: 'rgba(244, 63, 94, 0.15)', + border: '1px solid rgba(244, 63, 94, 0.3)' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), " Less Return Credit:"] + }), /*#__PURE__*/_jsxs("span", { + children: ["-₹", returnTotal.toFixed(2)] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-2 text-slate-300", + style: { + color: '#cbd5e1' + }, + children: [/*#__PURE__*/_jsx("span", { + children: "Round Off:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", roundOff] + })] + }), /*#__PURE__*/_jsx("hr", { + style: { + borderColor: 'rgba(255,255,255,0.15)' + } + }), refundPayable > 0 ? /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 mb-3 border border-warning", + style: { + background: 'rgba(245, 158, 11, 0.15)' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("span", { + className: "fs-6 fw-bold text-white", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-wallet2 text-warning me-1" + }), " REFUND TO PATIENT:"] + }), /*#__PURE__*/_jsxs("span", { + className: "fs-3 fw-bolder text-warning", + children: ["₹", refundPayable.toLocaleString('en-IN')] + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-white-50 d-block mt-1", + style: { + fontSize: '0.72rem' + }, + children: "Return credit exceeds new items. Refund this net difference from counter cash drawer or UPI." + }), /*#__PURE__*/_jsxs("div", { + className: "mt-2.5", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white small fw-bold mb-1", + children: "Refund Outflow Method" + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm w-100 mb-2", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${refundMode === 'Cash' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => setRefundMode('Cash'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-stack me-1" + }), " Cash Refund"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${refundMode === 'UPI' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => setRefundMode('UPI'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-qr-code me-1" + }), " UPI / Bank Refund"] + })] + }), refundMode === 'UPI' && /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-warning", + placeholder: "Patient UPI VPA or Bank Reference #", + value: refundRefNo, + onChange: e => setRefundRefNo(e.target.value) + })] + })] + }) : /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-4", + children: [/*#__PURE__*/_jsx("span", { + className: "fs-5 fw-bold text-white", + children: "Net Payable:" + }), /*#__PURE__*/_jsxs("span", { + className: "fs-3 fw-bolder text-warning", + children: ["₹", netPayable.toLocaleString('en-IN')] + })] + }), refundPayable <= 0 && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white fw-bold mb-0", + children: "Payment Method" + }), paymentMode === 'Mixed' && /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pie-chart me-1" + }), " Partial / Split Mode"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm w-100 ${paymentMode === 'Cash' ? 'btn-primary-custom' : 'btn-outline-light'}`, + onClick: () => setPaymentMode('Cash'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-stack me-1" + }), " Cash"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm w-100 ${paymentMode === 'UPI' ? 'btn-primary-custom' : 'btn-outline-light'}`, + onClick: () => setPaymentMode('UPI'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-qr-code-scan me-1" + }), " UPI / QR"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm w-100 ${paymentMode === 'Mixed' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => { + setPaymentMode('Mixed'); + if (!splitCash && !splitUpi) { + setSplitCash(''); + setSplitUpi(''); + } + }, + title: "Partial payment by Cash and UPI/Bank", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pie-chart-fill me-1" + }), " Split / Mixed"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm w-100 ${paymentMode === 'Card' ? 'btn-primary-custom' : 'btn-outline-light'}`, + onClick: () => setPaymentMode('Card'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-credit-card me-1" + }), " Card Swipe"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm w-100 ${paymentMode === 'IPD_Credit' ? 'btn-danger' : 'btn-outline-light'}`, + onClick: () => setPaymentMode('IPD_Credit'), + title: "Charge to IPD Patient Bill", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital me-1" + }), " IPD Bill Post"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-12 mt-1", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm w-100 ${paymentMode === 'Staff_Credit' ? 'btn-info text-dark fw-bold' : 'btn-outline-info'}`, + onClick: () => setPaymentMode('Staff_Credit'), + title: "Charge to Staff / Doctor / Customer Credit Ledger", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-lines-fill me-1" + }), " Staff / Doctor / Customer Credit A/c"] + }) + })] + }), paymentMode === 'Staff_Credit' && /*#__PURE__*/_jsxs("div", { + className: "card bg-dark border-info mb-3 p-2.5 rounded-3 text-white", + style: { + fontSize: '0.82rem' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom border-secondary", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-info", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-lines-fill me-1" + }), " Staff / Customer Credit Account"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-info text-dark", + children: "Ledger Debit" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label text-white-50 small mb-1", + children: ["Select Credit Account ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: selectedCreditAccount ? selectedCreditAccount.account_id : '', + onChange: e => { + const acc = creditAccounts.find(a => String(a.account_id) === e.target.value); + setSelectedCreditAccount(acc || null); + }, + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "-- Choose Account --" + }), creditAccounts.filter(a => a.is_active == 1).map(a => /*#__PURE__*/_jsxs("option", { + value: a.account_id, + children: [a.account_name, " (", a.account_type.toUpperCase(), ") - Dues: ₹", Number(a.current_balance || 0).toFixed(2)] + }, a.account_id))] + })] + }), selectedCreditAccount && /*#__PURE__*/_jsxs("div", { + className: "p-2 bg-secondary bg-opacity-25 rounded border border-secondary mb-1", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("span", { + className: "text-white-50", + children: "Dept / ID:" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold", + children: selectedCreditAccount.department || selectedCreditAccount.staff_id || 'N/A' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("span", { + className: "text-white-50", + children: "Current Outstanding:" + }), /*#__PURE__*/_jsxs("span", { + className: `fw-bold ${Number(selectedCreditAccount.current_balance) > 0 ? 'text-warning' : 'text-success'}`, + children: ["₹", Number(selectedCreditAccount.current_balance || 0).toFixed(2)] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("span", { + className: "text-white-50", + children: "Credit Limit:" + }), /*#__PURE__*/_jsxs("span", { + className: "fw-bold", + children: ["₹", Number(selectedCreditAccount.credit_limit || 0).toFixed(2)] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between border-top border-secondary pt-1 mt-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-white-50", + children: "Balance after this bill:" + }), /*#__PURE__*/_jsxs("span", { + className: "fw-bold text-info", + children: ["₹", (Number(selectedCreditAccount.current_balance || 0) + netPayable).toFixed(2)] + })] + })] + })] + }), paymentMode === 'IPD_Credit' && /*#__PURE__*/_jsxs("div", { + className: "alert alert-warning py-2 mb-3", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-info-circle me-1" + }), "Medicines will be charged directly to the patient's IPD Hospital Account and settled at discharge."] + }), paymentMode === 'Mixed' && /*#__PURE__*/_jsxs("div", { + className: "card bg-dark border-warning mb-3 p-2.5 rounded-3 text-white", + style: { + fontSize: '0.82rem' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom border-secondary", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-warning", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt-cutoff me-1" + }), " Split Payment Allocation"] + }), /*#__PURE__*/_jsxs("span", { + className: "fw-bold", + children: ["Total: ₹", netPayable] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white-50 mb-1", + style: { + fontSize: '0.75rem' + }, + children: "Cash Amount (₹)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-secondary border-0 text-white", + children: "₹" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "e.g. 35", + value: splitCash, + onChange: e => setSplitCash(e.target.value), + step: "any" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white-50 mb-1", + style: { + fontSize: '0.75rem' + }, + children: "UPI / Bank (₹)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-secondary border-0 text-white", + children: "₹" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "e.g. 100", + value: splitUpi, + onChange: e => setSplitUpi(e.target.value), + step: "any" + })] + })] + })] + }), Number(splitUpi) > 0 && /*#__PURE__*/_jsx("div", { + className: "p-2 rounded bg-black bg-opacity-25 border border-secondary mb-2", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-7", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label text-warning mb-0", + style: { + fontSize: '0.72rem' + }, + children: ["UPI UTR / Trans. Ref # ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-warning", + placeholder: "e.g. 425109876543 (12-digit)", + value: upiRefNo, + onChange: e => setUpiRefNo(e.target.value) + }), /*#__PURE__*/_jsx("span", { + style: { + fontSize: '0.65rem' + }, + className: "text-white-50", + children: "Used by Accountant for statement audit" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-5", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white-50 mb-0", + style: { + fontSize: '0.72rem' + }, + children: "Bank / QR" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "e.g. SBI, HDFC", + list: "commonBankList", + value: bankName, + onChange: e => setBankName(e.target.value) + }), /*#__PURE__*/_jsxs("datalist", { + id: "commonBankList", + children: [/*#__PURE__*/_jsx("option", { + value: "SBI" + }), /*#__PURE__*/_jsx("option", { + value: "HDFC Bank" + }), /*#__PURE__*/_jsx("option", { + value: "ICICI Bank" + }), /*#__PURE__*/_jsx("option", { + value: "Axis Bank" + }), /*#__PURE__*/_jsx("option", { + value: "Punjab National Bank" + }), /*#__PURE__*/_jsx("option", { + value: "Bank of Baroda" + }), /*#__PURE__*/_jsx("option", { + value: "Google Pay / PhonePe" + }), /*#__PURE__*/_jsx("option", { + value: "Paytm" + })] + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsx("span", { + style: { + fontSize: '0.75rem' + }, + className: "text-white-50", + children: "Card Swiped (if any):" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + style: { + width: 140 + }, + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-secondary border-0 text-white", + style: { + fontSize: '0.7rem' + }, + children: "₹" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "0", + value: splitCard, + onChange: e => setSplitCard(e.target.value), + step: "any" + })] + })] + }), Number(splitCard) > 0 && /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary mt-1", + placeholder: "Card Slip Auth / Ref No", + value: cardRefNo, + onChange: e => setCardRefNo(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "p-2 rounded bg-black bg-opacity-40 border border-secondary", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: ["Allocated: ", /*#__PURE__*/_jsxs("strong", { + children: ["₹", totalSplitAllocated.toFixed(2)] + })] + }), /*#__PURE__*/_jsxs("span", { + children: ["Bill Net: ", /*#__PURE__*/_jsxs("strong", { + children: ["₹", netPayable] + })] + })] + }), Math.abs(splitRemaining) <= 0.01 ? /*#__PURE__*/_jsxs("div", { + className: "text-success fw-bold d-flex align-items-center gap-1", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill" + }), " Balanced! Ready to print bill."] + }) : splitRemaining > 0 ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "text-warning fw-bold mb-1.5", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-circle me-1" + }), " Balance Remaining: ₹", splitRemaining.toFixed(2)] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-warning py-0", + style: { + fontSize: '0.7rem' + }, + onClick: () => setSplitUpi(String(((Number(splitUpi) || 0) + splitRemaining).toFixed(2))), + children: ["+ ₹", splitRemaining.toFixed(2), " to UPI"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-info py-0", + style: { + fontSize: '0.7rem' + }, + onClick: () => setSplitCash(String(((Number(splitCash) || 0) + splitRemaining).toFixed(2))), + children: ["+ ₹", splitRemaining.toFixed(2), " to Cash"] + })] + })] + }) : /*#__PURE__*/_jsxs("div", { + className: "text-danger fw-bold", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle-fill me-1" + }), " Overallocated by ₹", Math.abs(splitRemaining).toFixed(2)] + })] + })] + }), paymentMode === 'UPI' && /*#__PURE__*/_jsxs("div", { + className: "bg-dark p-2.5 rounded-3 mb-3 border border-secondary", + children: [store?.upi_id && /*#__PURE__*/_jsx("div", { + className: "text-center mb-2", + children: /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '0.75rem' + }, + children: ["Store UPI VPA: ", /*#__PURE__*/_jsx("span", { + className: "text-warning fw-bold", + children: store?.upi_id + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-7", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label text-white-50 mb-1", + style: { + fontSize: '0.72rem' + }, + children: ["UPI UTR / Ref No ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-warning", + placeholder: "12-digit UTR No", + value: upiRefNo, + onChange: e => setUpiRefNo(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-5", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white-50 mb-1", + style: { + fontSize: '0.72rem' + }, + children: "Bank Name" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "e.g. SBI, HDFC", + value: bankName, + onChange: e => setBankName(e.target.value) + })] + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-white-50 d-block mt-1", + style: { + fontSize: '0.68rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1 text-success" + }), " Accountant will match this UTR against the hospital bank statement."] + })] + }), paymentMode === 'Card' && /*#__PURE__*/_jsx("div", { + className: "bg-dark p-2.5 rounded-3 mb-3 border border-secondary", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-7", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white-50 mb-1", + style: { + fontSize: '0.72rem' + }, + children: "Card Slip / Auth Ref No" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "POS Machine Auth Code", + value: cardRefNo, + onChange: e => setCardRefNo(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-5", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white-50 mb-1", + style: { + fontSize: '0.72rem' + }, + children: "Bank / Terminal" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "e.g. HDFC EDC", + value: bankName, + onChange: e => setBankName(e.target.value) + })] + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-white small fw-bold mb-1", + children: "Invoice Print Format" + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm w-100", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${printFormat === 'thermal' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => setPrintFormat('thermal'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt me-1" + }), " Thermal (Text)"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${printFormat === 'a5' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => setPrintFormat('a5'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf me-1" + }), " A5 Landscape (PDF)"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${printFormat === 'a4' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light'}`, + onClick: () => setPrintFormat('a4'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf me-1" + }), " A4 (PDF)"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: `btn ${refundPayable > 0 ? 'btn-warning text-dark fw-bold' : 'btn-success-custom'} w-100 py-2.5 fs-6`, + onClick: processSale, + disabled: isProcessing || cart.length === 0 && returnCart.length === 0 || refundPayable === 0 && paymentMode === 'Mixed' && Math.abs(splitRemaining) > 0.01, + children: isProcessing ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split me-2" + }), " Generating Bill & Credit Note..."] + }) : refundPayable === 0 && paymentMode === 'Mixed' && Math.abs(splitRemaining) > 0.01 ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle me-2" + }), " Allocate Balance (₹", splitRemaining > 0 ? splitRemaining.toFixed(2) + ' left' : Math.abs(splitRemaining).toFixed(2) + ' over', ")"] + }) : refundPayable > 0 ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-2" + }), " Process Return & Refund ₹", refundPayable] + }) : returnCart.length > 0 ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left-right me-2" + }), " Complete Exchange Bill & Print (", printFormat === 'a5' ? 'A5 LANDSCAPE' : printFormat.toUpperCase(), ")"] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-2" + }), " Complete Sale & Print (", printFormat === 'a5' ? 'A5 LANDSCAPE' : printFormat.toUpperCase(), ")"] + }) + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: `print-drawer-overlay ${isPrintOpen ? 'open' : ''}`, + onClick: () => setIsPrintOpen(false) + }), /*#__PURE__*/_jsx("div", { + className: `print-drawer ${isPrintOpen ? 'open' : ''}`, + id: "pos-print-drawer", + children: lastInvoice && /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("div", { + className: "print-drawer-header", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt text-warning fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold text-white", + children: "Invoice & Print Desk" + }), /*#__PURE__*/_jsxs("small", { + className: "text-secondary", + style: { + fontSize: '0.72rem' + }, + children: ["Bill: ", /*#__PURE__*/_jsx("span", { + className: "text-info fw-bold", + children: lastInvoice.sale.invoice_no + }), lastInvoice.sale.abdm_care_context_ref && /*#__PURE__*/_jsxs("span", { + className: "ms-2 text-success", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check me-0.5" + }), " ABDM Linked"] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1.5 flex-wrap", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-outline-success text-white py-1 px-2", + onClick: () => viewAbdmBundle(lastInvoice.sale.sale_id), + title: "View official ABDM FHIR R4 MedicationDispense JSON Document Bundle", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-filetype-json me-1" + }), " FHIR R4"] + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-xs py-1 px-2 ${printFormat === 'thermal' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setPrintFormat('thermal'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt me-1" + }), " Thermal (Text)"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-xs py-1 px-2 ${printFormat === 'a5' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setPrintFormat('a5'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf me-1" + }), " A5 Landscape (PDF)"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-xs py-1 px-2 ${printFormat === 'a4' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setPrintFormat('a4'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf me-1" + }), " A4 (PDF)"] + })] + }), printFormat === 'thermal' ? /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-warning text-dark fw-bold py-1 px-2.5 ms-0.5", + onClick: printThermalReceipt, + title: "Print on 80mm Thermal Receipt Printer", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer-fill me-1" + }), " Print Thermal"] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-light py-1 px-2 text-white", + onClick: () => downloadPdf(printFormat), + title: `Download ${printFormat === 'a5' ? 'A5 Landscape' : printFormat.toUpperCase()} PDF Document`, + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1 text-info" + }), " PDF"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-primary py-1 px-2.5 ms-0.5 fw-bold", + onClick: () => printPdf(printFormat), + title: `Print Vector-Clean ${printFormat === 'a5' ? 'A5 Landscape' : printFormat.toUpperCase()} PDF`, + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF (", printFormat === 'a5' ? 'A5 LANDSCAPE' : printFormat.toUpperCase(), ")"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-light rounded-pill px-2.5 py-1 ms-1 d-flex align-items-center gap-1", + onClick: () => setIsPrintOpen(false), + title: "Close Print Drawer (Esc)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-lg" + }), /*#__PURE__*/_jsx("kbd", { + style: { + background: '#334155', + color: '#f8fafc', + fontSize: '0.62rem', + padding: '1px 3px', + borderRadius: '3px' + }, + children: "Esc" + })] + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "print-drawer-body", + children: /*#__PURE__*/_jsx("div", { + className: "print-paper-card", + children: /*#__PURE__*/_jsxs("div", { + id: "printable-container", + children: [printFormat === 'thermal' && /*#__PURE__*/_jsxs("div", { + className: "p-2 text-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2 mx-auto", + style: { + maxWidth: '360px' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-dark text-warning border border-secondary", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt me-1" + }), " 80mm Thermal Receipt (Plain Text)"] + }), /*#__PURE__*/_jsx("div", { + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-warning text-dark fw-bold py-0.5 px-2.5", + onClick: printThermalReceipt, + title: "Print Thermal 80mm Receipt", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer-fill me-1" + }), " Print Thermal"] + }) + })] + }), /*#__PURE__*/_jsx("pre", { + id: "thermal-receipt-preview", + style: { + fontFamily: "'Courier New', Courier, monospace", + fontSize: '11px', + lineHeight: '1.28', + backgroundColor: '#ffffff', + color: '#000000', + padding: '16px', + border: '1px solid #cbd5e1', + borderRadius: '6px', + boxShadow: '0 4px 15px rgba(0,0,0,0.06)', + width: '360px', + maxWidth: '100%', + margin: '0 auto', + textAlign: 'left', + whiteSpace: 'pre-wrap', + wordBreak: 'break-all' + }, + children: generateThermalReceiptText(lastInvoice) + })] + }), printFormat === 'a5' && /*#__PURE__*/_jsxs("div", { + className: "print-a5-invoice", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center bg-primary-subtle border border-primary-subtle rounded px-2.5 py-1.5 mb-2.5 no-print", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf-fill text-danger fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + style: { + fontSize: '0.78rem' + }, + children: "A5 Landscape Tax Invoice (PDF Ready)" + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '0.68rem' + }, + children: "Direct server vector PDF (Landscape: 210 × 148 mm) • Zero clipped columns" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1.5", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-outline-primary py-1 px-2", + onClick: () => downloadPdf('a5'), + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1" + }), " Download PDF"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-primary py-1 px-2.5 fw-bold", + onClick: () => printPdf('a5'), + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF (A5 Landscape)"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start border-bottom pb-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "fw-bold mb-0 text-primary", + children: lastInvoice.sale.store_name + }), /*#__PURE__*/_jsxs("div", { + style: { + fontSize: '10px' + }, + children: [lastInvoice.sale.building_name, ", ", lastInvoice.sale.floor_no, ", ", lastInvoice.sale.store_address] + }), /*#__PURE__*/_jsxs("div", { + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsx("strong", { + children: "DL 20B:" + }), " ", lastInvoice.sale.drug_license_no_20b, " | ", /*#__PURE__*/_jsx("strong", { + children: "DL 21B:" + }), " ", lastInvoice.sale.drug_license_no_21b, lastInvoice.sale.abdm_hfr_id && /*#__PURE__*/_jsxs("span", { + children: [" | ", /*#__PURE__*/_jsx("strong", { + children: "HFR ID:" + }), " ", lastInvoice.sale.abdm_hfr_id] + })] + }), /*#__PURE__*/_jsxs("div", { + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsx("strong", { + children: "GSTIN:" + }), " ", lastInvoice.sale.gstin, " | ", /*#__PURE__*/_jsx("strong", { + children: "Phone:" + }), " ", lastInvoice.sale.contact_phone] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-dark text-white mb-1", + children: "RETAIL TAX INVOICE" + }), /*#__PURE__*/_jsx("div", { + className: "fw-bold", + style: { + fontSize: '12px' + }, + children: lastInvoice.sale.invoice_no + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: lastInvoice.sale.sale_date + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-1 mb-2 p-1.5 bg-light rounded", + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("strong", { + children: "Patient:" + }), " ", lastInvoice.sale.patient_name, " ", lastInvoice.sale.uhid ? `(${lastInvoice.sale.uhid})` : ''] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("strong", { + children: "Prescribed By:" + }), " ", lastInvoice.sale.doctor_name] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("strong", { + children: "Age/Gender:" + }), " ", lastInvoice.sale.age || 'N/A', " / ", lastInvoice.sale.gender || 'N/A'] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("strong", { + children: "Payment Mode:" + }), " ", lastInvoice.sale.payment_mode] + }), (lastInvoice.sale.abha_id || lastInvoice.sale.abha_address) && /*#__PURE__*/_jsxs("div", { + className: "col-12 text-success fw-bold", + children: [/*#__PURE__*/_jsx("strong", { + children: "ABHA:" + }), " ", lastInvoice.sale.abha_id || 'N/A', " (", lastInvoice.sale.abha_address || 'N/A', ")", lastInvoice.sale.abdm_care_context_ref && /*#__PURE__*/_jsxs("span", { + children: [" | ", /*#__PURE__*/_jsx("strong", { + children: "Care Context:" + }), " ", lastInvoice.sale.abdm_care_context_ref] + })] + })] + }), /*#__PURE__*/_jsxs("table", { + className: "table table-bordered table-sm mb-2", + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Name" + }), /*#__PURE__*/_jsx("th", { + children: "HSN" + }), /*#__PURE__*/_jsx("th", { + children: "Batch" + }), /*#__PURE__*/_jsx("th", { + children: "Exp" + }), /*#__PURE__*/_jsx("th", { + children: "Qty & Unit" + }), /*#__PURE__*/_jsx("th", { + children: "Unit MRP (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Amount (₹)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: lastInvoice.items.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: 8, + className: "text-center text-muted py-2", + children: "No medicines dispensed on this bill (Return / Refund Only)" + }) + }) : lastInvoice.items.map((it, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: i + 1 + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: [it.item_name, it.snomed_ct_code && /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '8px' + }, + children: ["SNOMED: ", it.snomed_ct_code] + }), Number(it.units_per_pack) > 1 && /*#__PURE__*/_jsxs("div", { + className: "text-muted fw-normal", + style: { + fontSize: '8px' + }, + children: ["Pack: 1 Strip = ", it.units_per_pack, " Tabs"] + })] + }), /*#__PURE__*/_jsx("td", { + children: it.hsn_code + }), /*#__PURE__*/_jsx("td", { + children: it.batch_no + }), /*#__PURE__*/_jsx("td", { + children: it.expiry_date.substring(0, 7) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "fw-bold", + children: it.sell_unit === 'Tablet' ? `${it.total_units} Tab` : it.sell_unit === 'Combo' ? `${it.qty} Str + ${it.loose_qty} Tab` : Number(it.units_per_pack) > 1 ? `${it.qty} Strip` : `${it.qty} ${it.unit_pack || 'Unit'}` + }), Number(it.units_per_pack) > 1 && it.sell_unit !== 'Tablet' && /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '8px' + }, + children: ["(", it.total_units, " Tabs)"] + })] + }), /*#__PURE__*/_jsx("td", { + children: it.sell_unit === 'Tablet' ? /*#__PURE__*/_jsxs("span", { + children: ["₹", it.unit_price, " ", /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/tab" + })] + }) : /*#__PURE__*/_jsxs("span", { + children: ["₹", it.unit_mrp, " ", Number(it.units_per_pack) > 1 ? /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/strip" + }) : ''] + }) + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", it.total_amount] + })] + }, i)) + })] + }), lastInvoice.return_items && lastInvoice.return_items.length > 0 && /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center bg-danger-subtle px-2 py-1 rounded-top border border-bottom-0 border-danger-subtle text-danger", + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), " RETURNED / EXCHANGED MEDICINES"] + }), lastInvoice.credit_note && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger", + children: ["Credit Note: ", lastInvoice.credit_note.credit_note_no] + })] + }), /*#__PURE__*/_jsxs("table", { + className: "table table-bordered table-sm mb-0 text-danger border-danger-subtle", + style: { + fontSize: '9px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-danger", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Name" + }), /*#__PURE__*/_jsx("th", { + children: "Batch" + }), /*#__PURE__*/_jsx("th", { + children: "Original Bill" + }), /*#__PURE__*/_jsx("th", { + children: "Condition" + }), /*#__PURE__*/_jsx("th", { + children: "Returned Qty" + }), /*#__PURE__*/_jsx("th", { + children: "Credit Rate (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Credit Total (₹)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: lastInvoice.return_items.map((it, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: i + 1 + }), /*#__PURE__*/_jsx("td", { + className: "fw-bold text-decoration-line-through", + children: it.item_name + }), /*#__PURE__*/_jsx("td", { + children: it.batch_no + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("code", { + children: it.ref_invoice_no || 'N/A' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: it.return_condition + }) + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: ["-", it.sell_unit === 'Tablet' ? `${it.total_units} Tab` : `${it.qty} ${it.unit_pack || 'Unit'}`] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", it.unit_price] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["-₹", Math.abs(Number(it.total_amount)).toFixed(2)] + })] + }, `a5-ret-${i}`)) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center border-top pt-2", + children: [/*#__PURE__*/_jsxs("div", { + style: { + fontSize: '9px' + }, + children: ["R.Ph: ", lastInvoice.sale.registered_pharmacist_name || 'Pharmacist', " (", lastInvoice.sale.pharmacist_reg_no, ")", lastInvoice.sale.pharmacist_hpr_id && /*#__PURE__*/_jsxs("span", { + children: [" | HPR ID: ", lastInvoice.sale.pharmacist_hpr_id] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("div", { + style: { + fontSize: '10px' + }, + className: "text-muted", + children: ["Gross: ₹", lastInvoice.sale.gross_amount, Number(lastInvoice.sale.discount_amount) > 0 && /*#__PURE__*/_jsxs("span", { + className: "text-danger ms-2", + children: ["Disc: -₹", lastInvoice.sale.discount_amount] + }), Number(lastInvoice.sale.return_amount) > 0 && /*#__PURE__*/_jsxs("span", { + className: "text-danger fw-bold ms-2", + children: ["Return Credit: -₹", lastInvoice.sale.return_amount] + })] + }), /*#__PURE__*/_jsx("span", { + className: "fs-6 fw-bold text-primary", + children: Number(lastInvoice.sale.refund_amount) > 0 ? `NET REFUND: ₹${lastInvoice.sale.refund_amount}` : `TOTAL: ₹${lastInvoice.sale.net_amount}` + }), Number(lastInvoice.sale.refund_amount) > 0 && /*#__PURE__*/_jsxs("div", { + className: "text-danger fw-bold small", + children: ["Refund Paid via ", lastInvoice.sale.refund_mode, " ", lastInvoice.sale.refund_ref_no ? `[Ref: ${lastInvoice.sale.refund_ref_no}]` : ''] + }), /*#__PURE__*/_jsxs("div", { + style: { + fontSize: '9px' + }, + className: "text-muted mt-0.5", + children: [/*#__PURE__*/_jsxs("span", { + children: ["Settlement: ", /*#__PURE__*/_jsx("strong", { + children: lastInvoice.sale.payment_mode + })] + }), Number(lastInvoice.sale.cash_paid) > 0 && /*#__PURE__*/_jsxs("span", { + className: "ms-1.5", + children: ["Cash: ₹", lastInvoice.sale.cash_paid] + }), Number(lastInvoice.sale.upi_paid) > 0 && /*#__PURE__*/_jsxs("span", { + className: "ms-1.5", + children: ["UPI: ₹", lastInvoice.sale.upi_paid, " ", lastInvoice.sale.upi_ref_no ? `(UTR: ${lastInvoice.sale.upi_ref_no})` : ''] + }), Number(lastInvoice.sale.card_paid) > 0 && /*#__PURE__*/_jsxs("span", { + className: "ms-1.5", + children: ["Card: ₹", lastInvoice.sale.card_paid] + }), lastInvoice.sale.is_bank_reconciled == 1 && /*#__PURE__*/_jsx("span", { + className: "ms-1.5 text-success fw-bold", + children: "✓ Audited" + })] + })] + })] + })] + }), printFormat === 'a4' && /*#__PURE__*/_jsxs("div", { + className: "print-a4-invoice", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center bg-primary-subtle border border-primary-subtle rounded px-3 py-1.5 mb-3 no-print", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf-fill text-danger fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + style: { + fontSize: '0.8rem' + }, + children: "A4 Hospital GST Tax Invoice (PDF Ready)" + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '0.68rem' + }, + children: "Server-rendered vector PDF • Zero clipped columns" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1.5", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-outline-primary py-1 px-2.5", + onClick: () => downloadPdf('a4'), + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1" + }), " Download PDF"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-primary py-1 px-2.5 fw-bold", + onClick: () => printPdf('a4'), + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center border-bottom pb-3 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h4", { + className: "fw-bold text-primary mb-1", + children: lastInvoice.sale.store_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + children: [lastInvoice.sale.building_name, ", ", lastInvoice.sale.floor_no, ", ", lastInvoice.sale.store_address] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Drug License 20-B:" + }), " ", lastInvoice.sale.drug_license_no_20b, " | ", /*#__PURE__*/_jsx("strong", { + children: "21-B:" + }), " ", lastInvoice.sale.drug_license_no_21b, " | ", /*#__PURE__*/_jsx("strong", { + children: "FSSAI:" + }), " ", lastInvoice.sale.fssai_no || 'N/A'] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("strong", { + children: "GSTIN:" + }), " ", lastInvoice.sale.gstin, " | ", /*#__PURE__*/_jsx("strong", { + children: "State:" + }), " ", lastInvoice.sale.state_name, " (Code: ", lastInvoice.sale.state_code, ")", lastInvoice.sale.abdm_hfr_id && /*#__PURE__*/_jsxs("span", { + children: [" | ", /*#__PURE__*/_jsx("strong", { + children: "ABDM HFR Facility ID:" + }), " ", lastInvoice.sale.abdm_hfr_id] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-primary fs-6 px-3 py-1.5 mb-1", + children: "HOSPITAL GST TAX INVOICE" + }), /*#__PURE__*/_jsx("h5", { + className: "fw-bold mb-0 text-dark", + children: lastInvoice.sale.invoice_no + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted small", + children: ["Date & Time: ", lastInvoice.sale.sale_date] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3 p-2 bg-light rounded border", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-4", + children: [/*#__PURE__*/_jsx("strong", { + children: "Patient Name:" + }), " ", lastInvoice.sale.patient_name] + }), /*#__PURE__*/_jsxs("div", { + className: "col-4", + children: [/*#__PURE__*/_jsx("strong", { + children: "UHID No:" + }), " ", /*#__PURE__*/_jsx("code", { + className: "text-primary fw-bold", + children: lastInvoice.sale.uhid || 'Walk-in' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-4", + children: [/*#__PURE__*/_jsx("strong", { + children: "Phone:" + }), " ", lastInvoice.sale.patient_mobile || 'N/A'] + }), /*#__PURE__*/_jsxs("div", { + className: "col-4", + children: [/*#__PURE__*/_jsx("strong", { + children: "Age / Gender:" + }), " ", lastInvoice.sale.age || 'N/A', " / ", lastInvoice.sale.gender || 'N/A'] + }), /*#__PURE__*/_jsxs("div", { + className: "col-4", + children: [/*#__PURE__*/_jsx("strong", { + children: "Consultant Doctor:" + }), " ", lastInvoice.sale.doctor_name] + }), /*#__PURE__*/_jsxs("div", { + className: "col-4", + children: [/*#__PURE__*/_jsx("strong", { + children: "Doctor Reg No:" + }), " ", lastInvoice.sale.doctor_reg_no || 'N/A'] + }), (lastInvoice.sale.abha_id || lastInvoice.sale.abha_address) && /*#__PURE__*/_jsxs("div", { + className: "col-12 bg-success-subtle p-1.5 rounded text-success fw-bold border border-success mt-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check me-1" + }), " ABDM Linked: ABHA Number: ", lastInvoice.sale.abha_id || 'N/A', " | ABHA Address: ", lastInvoice.sale.abha_address || 'N/A', " | Care Context: ", lastInvoice.sale.abdm_care_context_ref || 'N/A'] + }), lastInvoice.sale.ipd_id && /*#__PURE__*/_jsxs("div", { + className: "col-12 text-danger fw-bold border-top pt-1 mt-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital me-1" + }), " IPD Admission #", lastInvoice.sale.ipd_id, " • Ward: ", lastInvoice.sale.ward_name || 'General', " • Bed: ", lastInvoice.sale.bed_no || 'Bed', " (Charged to IPD Running Bill)"] + })] + }), /*#__PURE__*/_jsxs("table", { + className: "table table-bordered mb-3", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 40 + }, + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine & Formulation" + }), /*#__PURE__*/_jsx("th", { + children: "HSN" + }), /*#__PURE__*/_jsx("th", { + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + children: "Exp Date" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 105 + }, + children: "Qty & Unit" + }), /*#__PURE__*/_jsx("th", { + children: "Rate (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "Taxable (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "CGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "SGST (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Total (₹)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: lastInvoice.items.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: 11, + className: "text-center text-muted py-3", + children: "No medicines dispensed on this bill (Pure Sales Return & Customer Refund)" + }) + }) : lastInvoice.items.map((it, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: i + 1 + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: [it.item_name, it.snomed_ct_code && /*#__PURE__*/_jsxs("div", { + className: "text-muted fw-normal", + style: { + fontSize: '9px' + }, + children: ["SNOMED-CT: ", /*#__PURE__*/_jsx("code", { + children: it.snomed_ct_code + }), " (", it.snomed_display || '', ")"] + }), Number(it.units_per_pack) > 1 && /*#__PURE__*/_jsxs("div", { + className: "text-muted fw-normal", + style: { + fontSize: '9px' + }, + children: ["Packing: 1 Strip of ", it.units_per_pack, " Tablets"] + })] + }), /*#__PURE__*/_jsx("td", { + children: it.hsn_code + }), /*#__PURE__*/_jsx("td", { + children: it.batch_no + }), /*#__PURE__*/_jsx("td", { + children: it.expiry_date + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "fw-bold", + children: it.sell_unit === 'Tablet' ? `${it.total_units} Tab` : it.sell_unit === 'Combo' ? `${it.qty} Str + ${it.loose_qty} Tab` : Number(it.units_per_pack) > 1 ? `${it.qty} Strip` : `${it.qty} ${it.unit_pack || 'Unit'}` + }), Number(it.units_per_pack) > 1 && it.sell_unit !== 'Tablet' && /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '9px' + }, + children: ["(", it.total_units, " Tablets)"] + })] + }), /*#__PURE__*/_jsx("td", { + children: it.sell_unit === 'Tablet' ? /*#__PURE__*/_jsxs("span", { + children: ["₹", it.unit_price, " ", /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/tab" + })] + }) : /*#__PURE__*/_jsxs("span", { + children: ["₹", it.unit_mrp, " ", Number(it.units_per_pack) > 1 ? /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/strip" + }) : ''] + }) + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", it.taxable_value] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", it.cgst_amount] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", it.sgst_amount] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", it.total_amount] + })] + }, i)) + })] + }), lastInvoice.return_items && lastInvoice.return_items.length > 0 && /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center bg-danger-subtle p-2 rounded-top border border-bottom-0 border-danger text-danger", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), " GST CREDIT NOTE / RETURNED & EXCHANGED MEDICINES"] + }), lastInvoice.credit_note && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger fs-7", + children: ["Credit Note No: ", lastInvoice.credit_note.credit_note_no, " (", lastInvoice.credit_note.return_date, ")"] + })] + }), /*#__PURE__*/_jsxs("table", { + className: "table table-bordered mb-0 text-danger border-danger", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-danger", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 40 + }, + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Returned Medicine & Formulation" + }), /*#__PURE__*/_jsx("th", { + children: "HSN" + }), /*#__PURE__*/_jsx("th", { + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + children: "Original Invoice" + }), /*#__PURE__*/_jsx("th", { + children: "Condition / Reason" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 105 + }, + children: "Qty Returned" + }), /*#__PURE__*/_jsx("th", { + children: "Credit Rate (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "Taxable (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "CGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "SGST (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Credit Total (₹)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: lastInvoice.return_items.map((it, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: i + 1 + }), /*#__PURE__*/_jsx("td", { + className: "fw-bold text-decoration-line-through", + children: it.item_name + }), /*#__PURE__*/_jsx("td", { + children: it.hsn_code + }), /*#__PURE__*/_jsx("td", { + children: it.batch_no + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("code", { + children: it.ref_invoice_no || 'N/A' + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-secondary me-1", + children: it.return_condition + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: it.return_reason + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: "fw-bold", + children: ["-", it.sell_unit === 'Tablet' ? `${it.total_units} Tab` : `${it.qty} ${it.unit_pack || 'Unit'}`] + }) + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", it.unit_price] + }), /*#__PURE__*/_jsxs("td", { + children: ["-₹", Math.abs(Number(it.taxable_value)).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["-₹", Math.abs(Number(it.cgst_amount)).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["-₹", Math.abs(Number(it.sgst_amount)).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["-₹", Math.abs(Number(it.total_amount)).toFixed(2)] + })] + }, `a4-ret-${i}`)) + })] + })] + }), lastInvoice.hsn_summary && lastInvoice.hsn_summary.length > 0 && /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "GST Tax Breakdown" + }), /*#__PURE__*/_jsxs("table", { + className: "table table-sm table-bordered text-center", + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "HSN Code" + }), /*#__PURE__*/_jsx("th", { + children: "GST Rate" + }), /*#__PURE__*/_jsx("th", { + children: "Taxable Value (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "CGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "SGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "Total Tax (₹)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: lastInvoice.hsn_summary.map((h, idx) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: h.hsn_code + }), /*#__PURE__*/_jsxs("td", { + children: [h.gst_rate, "%"] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", h.taxable_value.toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", h.cgst_amount.toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", h.sgst_amount.toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: ["₹", h.total_tax.toFixed(2)] + })] + }, idx)) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 border-top pt-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-7", + children: [/*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + children: [/*#__PURE__*/_jsx("strong", { + children: "Registered Pharmacist:" + }), " ", lastInvoice.sale.registered_pharmacist_name || 'Pharmacist', " (Reg No: ", lastInvoice.sale.pharmacist_reg_no || 'N/A', ")", lastInvoice.sale.pharmacist_hpr_id && /*#__PURE__*/_jsxs("span", { + children: [" | ", /*#__PURE__*/_jsx("strong", { + children: "HPR ID:" + }), " ", lastInvoice.sale.pharmacist_hpr_id] + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted d-block mt-1", + children: lastInvoice.sale.terms_conditions || '1. Goods once sold are returnable only as per Drug Rules.\n2. Store medicines below 25°C.' + }), /*#__PURE__*/_jsxs("div", { + className: "mt-2 p-2 bg-light rounded border", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark mb-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-wallet2 me-1" + }), " Payment Settlement:"] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-2 align-items-center mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: lastInvoice.sale.payment_mode + }), Number(lastInvoice.sale.cash_paid) > 0 && /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Cash:" + }), " ₹", lastInvoice.sale.cash_paid] + }), Number(lastInvoice.sale.upi_paid) > 0 && /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "UPI / Bank:" + }), " ₹", lastInvoice.sale.upi_paid, lastInvoice.sale.upi_ref_no && /*#__PURE__*/_jsxs("code", { + className: "text-primary ms-1", + children: ["[UTR: ", lastInvoice.sale.upi_ref_no, "]"] + }), lastInvoice.sale.bank_name && /*#__PURE__*/_jsxs("span", { + className: "text-muted ms-1", + children: ["(", lastInvoice.sale.bank_name, ")"] + })] + }), Number(lastInvoice.sale.card_paid) > 0 && /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Card:" + }), " ₹", lastInvoice.sale.card_paid, " ", lastInvoice.sale.card_ref_no ? `[Ref: ${lastInvoice.sale.card_ref_no}]` : ''] + }), Number(lastInvoice.sale.credit_amount) > 0 && /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Hospital Credit:" + }), " ₹", lastInvoice.sale.credit_amount] + })] + }), Number(lastInvoice.sale.refund_amount) > 0 && /*#__PURE__*/_jsx("div", { + className: "mb-1", + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-stack me-1" + }), " Refund Issued: ₹", lastInvoice.sale.refund_amount, " via ", lastInvoice.sale.refund_mode, " ", lastInvoice.sale.refund_ref_no ? `[Ref: ${lastInvoice.sale.refund_ref_no}]` : ''] + }) + }), /*#__PURE__*/_jsx("div", { + children: lastInvoice.sale.is_bank_reconciled == 1 ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-patch-check-fill me-1" + }), " Bank Statement Reconciled & Audited"] + }) : /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning-subtle text-dark border border-warning", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1" + }), " Bank Statement: Pending Audit"] + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-5", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + children: "Gross Items Total:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.gross_amount] + })] + }), Number(lastInvoice.sale.discount_amount) > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1 text-danger", + children: [/*#__PURE__*/_jsx("span", { + children: "Total Discounts Allowed:" + }), /*#__PURE__*/_jsxs("span", { + children: ["-₹", lastInvoice.sale.discount_amount] + })] + }), Number(lastInvoice.sale.return_amount) > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1 text-danger fw-bold", + children: [/*#__PURE__*/_jsx("span", { + children: "Less Return / Exchange Credit:" + }), /*#__PURE__*/_jsxs("span", { + children: ["-₹", lastInvoice.sale.return_amount] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + children: "Taxable Amount:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.taxable_amount] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + children: "CGST Amount:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.cgst_amount] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + children: "SGST Amount:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.sgst_amount] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + children: "Round Off:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.round_off] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between fs-5 fw-bolder border-top pt-2 text-primary", + children: [/*#__PURE__*/_jsx("span", { + children: "GRAND TOTAL / NET PAYABLE:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.net_amount] + })] + }), Number(lastInvoice.sale.refund_amount) > 0 && /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between fs-6 fw-bold text-danger border-top border-bottom py-1 mt-2", + children: [/*#__PURE__*/_jsx("span", { + children: "REFUND PAID TO CUSTOMER:" + }), /*#__PURE__*/_jsxs("span", { + children: ["₹", lastInvoice.sale.refund_amount, " (", lastInvoice.sale.refund_mode, lastInvoice.sale.refund_ref_no ? ` - ${lastInvoice.sale.refund_ref_no}` : '', ")"] + })] + })] + })] + })] + })] + }) + }) + }), /*#__PURE__*/_jsxs("div", { + className: "p-2.5 bg-white border-top d-flex justify-content-between align-items-center flex-shrink-0 px-3", + children: [/*#__PURE__*/_jsxs("span", { + className: "text-muted small", + children: ["Format: ", /*#__PURE__*/_jsx("strong", { + className: "text-dark text-uppercase", + children: printFormat + }), " • Bill No: ", /*#__PURE__*/_jsx("strong", { + children: lastInvoice.sale.invoice_no + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2 flex-wrap align-items-center", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-secondary px-3", + onClick: () => setIsPrintOpen(false), + children: "Done / Close (Esc)" + }), printFormat === 'thermal' ? /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-warning text-dark px-3 fw-bold", + onClick: printThermalReceipt, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer-fill me-1" + }), " Print Thermal Receipt"] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-primary px-3", + onClick: () => downloadPdf(printFormat), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1" + }), " Download PDF"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-primary px-3 fw-bold", + onClick: () => printPdf(printFormat), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF (", printFormat === 'a5' ? 'A5 LANDSCAPE' : printFormat.toUpperCase(), ")"] + })] + })] + })] + })] + }) + }), showFhirModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-lg modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2 px-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check text-success fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: "ABDM NRCES FHIR R4 MedicationDispense Document" + }), /*#__PURE__*/_jsx("small", { + className: "text-secondary", + style: { + fontSize: '0.75rem' + }, + children: "Profile: MedicationDispenseDocument | LOINC: 60590-7" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowFhirModal(false) + })] + }), /*#__PURE__*/_jsx("div", { + className: "modal-body p-3 bg-light", + children: isLoadingFhir ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-5", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border text-primary mb-2", + role: "status" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + children: "Retrieving & Validating ABDM FHIR R4 Bundle..." + })] + }) : fhirBundleData ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "bg-white p-2 rounded border", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted d-block", + children: "Care Context Reference" + }), /*#__PURE__*/_jsx("code", { + className: "text-primary fw-bold", + children: fhirBundleData.care_context_ref + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "bg-white p-2 rounded border", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted d-block", + children: "ABHA Number / Address" + }), /*#__PURE__*/_jsx("strong", { + className: "text-success", + children: fhirBundleData.abha_id || fhirBundleData.abha_address || 'Not ABHA Linked' + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "bg-white p-2 rounded border", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted d-block", + children: "Gateway Sync Status" + }), /*#__PURE__*/_jsx("span", { + className: `badge ${fhirBundleData.sync_status === 'SYNCED' ? 'bg-success' : 'bg-warning text-dark'}`, + children: fhirBundleData.sync_status || 'QUEUED_FOR_BRIDGE' + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "small fw-bold text-dark", + children: "NRCES FHIR R4 Document Bundle (JSON):" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-secondary py-0 px-2", + onClick: copyFhirToClipboard, + children: [/*#__PURE__*/_jsx("i", { + className: `bi ${copiedFhir ? 'bi-check-lg text-success' : 'bi-clipboard'} me-1` + }), copiedFhir ? 'Copied!' : 'Copy JSON'] + })] + }), /*#__PURE__*/_jsx("pre", { + className: "bg-dark text-light p-3 rounded-2", + style: { + maxHeight: 360, + fontSize: '0.75rem', + overflow: 'auto' + }, + children: JSON.stringify(fhirBundleData.bundle, null, 2) + })] + }) : /*#__PURE__*/_jsx("div", { + className: "alert alert-warning mb-0", + children: "No FHIR bundle data found." + }) + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-1 px-3 bg-white", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted me-auto", + style: { + fontSize: '0.75rem' + }, + children: "Includes SNOMED-CT clinical codes, HFR Facility ID, and Practitioner HPR ID." + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-secondary", + onClick: () => setShowFhirModal(false), + children: "Close" + })] + })] + }) + }) + }), showReturnModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-xl modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2 px-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left-right text-warning fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: "Sales Return & Same-Invoice Exchange Desk" + }), /*#__PURE__*/_jsx("small", { + className: "text-secondary", + style: { + fontSize: '0.75rem' + }, + children: "B2C Retail Returns • Stock Replenishment • GST Credit Note • Fast POS Standard (F6 / Alt+R)" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowReturnModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3 bg-light", + children: [/*#__PURE__*/_jsx("div", { + className: "card shadow-sm border-0 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "card-body p-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Lookup Original Tax Invoice / Patient UHID / Phone:" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + ref: returnSearchInputRef, + className: "form-control", + placeholder: "Enter Invoice No (e.g. MAIN/26-27/08176), UHID, Patient Name, or Mobile...", + value: returnSearchQuery, + onChange: e => setReturnSearchQuery(e.target.value), + onKeyDown: e => { + if (e.key === 'Enter') { + e.preventDefault(); + searchReturnInvoices(); + } + } + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-primary px-3", + type: "button", + disabled: isSearchingReturn, + onClick: () => searchReturnInvoices(), + children: isSearchingReturn ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-1" + }), "Searching..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-repeat me-1" + }), " Search Bill"] + }) + })] + })] + }) + }), !selectedReturnInvoice && returnSearchResults.length > 1 && /*#__PURE__*/_jsxs("div", { + className: "card shadow-sm border-0 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2 fw-bold text-dark small", + children: ["Matching Invoices (", returnSearchResults.length, " found) - Select an invoice to process returns:"] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + style: { + maxHeight: '220px' + }, + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover table-sm align-middle mb-0", + style: { + fontSize: '0.85rem' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Bill No" + }), /*#__PURE__*/_jsx("th", { + children: "Date" + }), /*#__PURE__*/_jsx("th", { + children: "Patient" + }), /*#__PURE__*/_jsx("th", { + children: "Doctor" + }), /*#__PURE__*/_jsx("th", { + children: "Original Net" + }), /*#__PURE__*/_jsx("th", { + children: "Returnable Items" + }), /*#__PURE__*/_jsx("th", { + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: returnSearchResults.map(resObj => { + const returnableCount = (resObj.items || []).filter(it => it.remaining_units > 0).length; + return /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-bold text-primary", + children: resObj.sale.invoice_no + }), /*#__PURE__*/_jsx("td", { + className: "text-muted", + children: resObj.sale.sale_date + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("strong", { + children: resObj.sale.patient_name + }), resObj.sale.uhid && /*#__PURE__*/_jsxs("span", { + className: "text-muted ms-1", + children: ["(", resObj.sale.uhid, ")"] + })] + }), /*#__PURE__*/_jsx("td", { + children: resObj.sale.doctor_name || 'N/A' + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: ["₹", resObj.sale.net_amount] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: `badge ${returnableCount > 0 ? 'bg-success-subtle text-success' : 'bg-secondary'}`, + children: [returnableCount, " items eligible"] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary py-0 px-2", + onClick: () => selectReturnInvoice(resObj), + children: ["Select Bill ", /*#__PURE__*/_jsx("i", { + className: "bi bi-chevron-right ms-1" + })] + }) + })] + }, resObj.sale.sale_id); + }) + })] + }) + })] + }), selectedReturnInvoice && /*#__PURE__*/_jsxs("div", { + className: "card shadow-sm border-0 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-primary fs-7", + children: selectedReturnInvoice.sale.invoice_no + }), /*#__PURE__*/_jsxs("span", { + className: "text-muted small", + children: ["Date: ", selectedReturnInvoice.sale.sale_date] + }), selectedReturnInvoice.sale.uhid && /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border", + children: ["UHID: ", selectedReturnInvoice.sale.uhid] + })] + }), returnSearchResults.length > 1 && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-0", + onClick: () => setSelectedReturnInvoice(null), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left me-1" + }), " Change Bill"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "card-body p-2 bg-light-subtle", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2 small", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("strong", { + children: "Patient:" + }), " ", selectedReturnInvoice.sale.patient_name] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("strong", { + children: "Phone:" + }), " ", selectedReturnInvoice.sale.patient_mobile || 'N/A'] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("strong", { + children: "Doctor:" + }), " ", selectedReturnInvoice.sale.doctor_name || 'N/A'] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("strong", { + children: "Original Net Paid:" + }), " ₹", selectedReturnInvoice.sale.net_amount] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-bordered table-sm align-middle mb-0", + style: { + fontSize: '0.85rem' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Name" + }), /*#__PURE__*/_jsx("th", { + children: "Batch / Exp" + }), /*#__PURE__*/_jsx("th", { + children: "Sold / Returned" + }), /*#__PURE__*/_jsx("th", { + children: "Eligible Units" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 150 + }, + children: "Return Qty & Unit" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 140 + }, + children: "Condition" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 150 + }, + children: "Reason" + }), /*#__PURE__*/_jsx("th", { + children: "Credit Rate" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 110 + }, + children: "Line Credit" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: selectedReturnInvoice.items.map((it, idx) => { + const draft = returnDraftItems[it.sale_item_id] || { + return_qty: 0, + return_unit: it.units_per_pack > 1 && it.remaining_strips > 0 ? 'Strip' : 'Tab', + condition: 'GOOD', + reason: 'EXCESS_UNUSED' + }; + const isEligible = it.remaining_units > 0; + const qty = Number(draft.return_qty) || 0; + const upp = Number(it.units_per_pack) || 1; + const totalReturnUnits = draft.return_unit === 'Strip' ? qty * upp : qty; + const lineCredit = Number((totalReturnUnits * it.effective_unit_price).toFixed(2)); + const isOverLimit = totalReturnUnits > it.remaining_units; + return /*#__PURE__*/_jsxs("tr", { + className: !isEligible ? 'opacity-50 table-light' : qty > 0 ? 'table-warning' : '', + children: [/*#__PURE__*/_jsx("td", { + children: idx + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("strong", { + className: "text-dark", + children: it.item_name + }), it.generic_name && /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.75rem' + }, + children: it.generic_name + }), upp > 1 && /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: ["1 Strip = ", upp, " Tabs"] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-dark border", + children: it.batch_no + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: ["Exp: ", it.expiry_date ? it.expiry_date.substring(0, 7) : 'N/A'] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + children: ["Sold: ", it.total_units, " tab"] + }), Number(it.already_returned_units) > 0 && /*#__PURE__*/_jsxs("div", { + className: "text-danger", + style: { + fontSize: '0.75rem' + }, + children: ["Returned: ", it.already_returned_units, " tab"] + })] + }), /*#__PURE__*/_jsx("td", { + children: isEligible ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success", + children: [it.remaining_units, " Tabs ", upp > 1 ? `(${it.remaining_strips} Str + ${it.remaining_loose} Tab)` : ''] + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: "Fully Returned" + }) + }), /*#__PURE__*/_jsxs("td", { + children: [isEligible ? /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + min: "0", + max: draft.return_unit === 'Strip' ? it.remaining_strips : it.remaining_units, + className: `form-control ${isOverLimit ? 'is-invalid' : ''}`, + value: draft.return_qty, + onChange: e => updateReturnDraft(it.sale_item_id, 'return_qty', e.target.value) + }), upp > 1 && /*#__PURE__*/_jsxs("select", { + className: "form-select", + style: { + maxWidth: 80 + }, + value: draft.return_unit, + onChange: e => updateReturnDraft(it.sale_item_id, 'return_unit', e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "Tab", + children: "Tab" + }), /*#__PURE__*/_jsx("option", { + value: "Strip", + children: "Strip" + })] + })] + }) : /*#__PURE__*/_jsx("span", { + className: "text-muted small", + children: "-" + }), isOverLimit && /*#__PURE__*/_jsxs("small", { + className: "text-danger d-block", + children: ["Max ", it.remaining_units, " tabs"] + })] + }), /*#__PURE__*/_jsx("td", { + children: isEligible && qty > 0 ? /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: draft.condition, + onChange: e => updateReturnDraft(it.sale_item_id, 'condition', e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "GOOD", + children: "Good (Restock)" + }), /*#__PURE__*/_jsx("option", { + value: "DAMAGED", + children: "Damaged / Broken" + }), /*#__PURE__*/_jsx("option", { + value: "EXPIRED", + children: "Expired / Defective" + })] + }) : /*#__PURE__*/_jsx("span", { + className: "text-muted small", + children: "-" + }) + }), /*#__PURE__*/_jsx("td", { + children: isEligible && qty > 0 ? /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: draft.reason, + onChange: e => updateReturnDraft(it.sale_item_id, 'reason', e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "EXCESS_UNUSED", + children: "Excess / Unused" + }), /*#__PURE__*/_jsx("option", { + value: "DOCTOR_CHANGED_RX", + children: "Doctor Changed Rx" + }), /*#__PURE__*/_jsx("option", { + value: "PATIENT_DISCHARGED", + children: "Patient Discharged" + }), /*#__PURE__*/_jsx("option", { + value: "WRONG_MEDICINE", + children: "Wrong Dispense" + })] + }) : /*#__PURE__*/_jsx("span", { + className: "text-muted small", + children: "-" + }) + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", it.effective_unit_price, " ", /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "/tab" + }), upp > 1 && /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: ["₹", (it.effective_unit_price * upp).toFixed(2), "/str"] + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-end fw-bold", + children: qty > 0 ? /*#__PURE__*/_jsxs("span", { + className: "text-danger", + children: ["-₹", lineCredit.toFixed(2)] + }) : /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "₹0.00" + }) + })] + }, it.sale_item_id); + }) + })] + }) + })] + }), !selectedReturnInvoice && returnSearchResults.length === 0 && /*#__PURE__*/_jsxs("div", { + className: "text-center py-5 text-muted bg-white rounded border", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt-cutoff fs-1 text-secondary mb-2 d-block" + }), /*#__PURE__*/_jsx("div", { + className: "fw-bold", + children: "No Invoice Selected" + }), /*#__PURE__*/_jsx("div", { + className: "small", + children: "Search by Bill Number, Patient UHID, Name, or Mobile to load returnable items." + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-white d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsx("div", { + children: selectedReturnInvoice && /*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center gap-3", + children: (() => { + let totalCredit = 0; + let totalItemsCount = 0; + selectedReturnInvoice.items.forEach(it => { + const draft = returnDraftItems[it.sale_item_id]; + if (draft && Number(draft.return_qty) > 0) { + const qty = Number(draft.return_qty); + const upp = Number(it.units_per_pack) || 1; + const tu = draft.return_unit === 'Strip' ? qty * upp : qty; + totalCredit += tu * it.effective_unit_price; + totalItemsCount++; + } + }); + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("span", { + className: "text-muted small me-2", + children: ["Selected Items: ", /*#__PURE__*/_jsx("strong", { + children: totalItemsCount + })] + }), /*#__PURE__*/_jsxs("span", { + className: "text-danger fw-bold fs-6", + children: ["Total Return Credit: -₹", totalCredit.toFixed(2)] + })] + }); + })() + }) + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-secondary btn-sm", + onClick: () => setShowReturnModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-danger btn-sm px-3 fw-bold", + disabled: !selectedReturnInvoice, + onClick: addSelectedReturnsToBill, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-plus me-1" + }), " Add to Current Bill (Exchange / Net-Off)"] + })] + })] + })] + }) + }) + }), showDraftModal && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + tabIndex: "-1", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content shadow-lg border-0", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone-vibrate text-warning fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold mb-0", + children: "Mobile App Rack Drafts Queue" + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Draft bills collected from pharmacy shelves via smartphone" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowDraftModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-3 pb-2 border-bottom", + children: [/*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm ${draftModalTab === 'DRAFT' ? 'btn-warning text-dark fw-bold' : 'btn-outline-secondary'}`, + onClick: () => { + setDraftModalTab('DRAFT'); + loadDraftBills('DRAFT'); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split me-1" + }), " Pending Queue"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm ${draftModalTab === 'CONVERTED' ? 'btn-success text-white fw-bold' : 'btn-outline-secondary'}`, + onClick: () => { + setDraftModalTab('CONVERTED'); + loadDraftBills('CONVERTED'); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-all me-1" + }), " Billed / Converted"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary py-0.5 px-2", + onClick: () => loadDraftBills(draftModalTab), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise me-1" + }), " Refresh"] + })] + }), draftBillsList.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-basket3 fs-1 d-block mb-2 text-secondary" + }), /*#__PURE__*/_jsx("h5", { + children: draftModalTab === 'CONVERTED' ? 'No Converted Draft Bills' : 'No Pending Draft Bills' + }), /*#__PURE__*/_jsx("p", { + className: "small mb-0", + children: draftModalTab === 'CONVERTED' ? 'Draft bills will appear here once converted into pharmacy sales invoices.' : 'Medicines added by rack collectors from the mobile app will automatically show up here.' + })] + }) : /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos table-hover mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Draft Code" + }), /*#__PURE__*/_jsx("th", { + children: "Patient / Ward" + }), /*#__PURE__*/_jsx("th", { + children: "Items" + }), /*#__PURE__*/_jsx("th", { + children: "Est. Amount" + }), /*#__PURE__*/_jsx("th", { + children: "Collector" + }), /*#__PURE__*/_jsx("th", { + children: "Time" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: draftBillsList.map(d => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge ${d.status === 'CONVERTED' ? 'bg-secondary' : 'bg-warning text-dark'} fw-bold`, + children: d.draft_code + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold", + children: d.patient_name || 'Walk-in' + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: d.ward_name ? `${d.ward_name} / Bed ${d.bed_no}` : d.patient_mobile || 'No bed info' + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary rounded-pill", + children: [d.total_items, " items"] + }) + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold text-success", + children: ["₹", Number(d.estimated_amount || 0).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("small", { + className: "text-secondary", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person me-1" + }), d.collected_by_name || 'Staff'] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: d.created_at?.split(' ')[1] || d.created_at + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end", + children: d.status === 'CONVERTED' ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success fw-bold px-2 py-1", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-1" + }), " Billed: ", d.converted_invoice_no || 'INV'] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-success fw-bold px-2.5 py-1 me-1 shadow-sm", + onClick: () => handleLoadDraftBillIntoCart(d), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-plus me-1" + }), " Load Bill"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-danger py-1 px-1.5", + onClick: () => handleCancelDraft(d.draft_id), + title: "Discard draft", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-trash" + }) + })] + }) + })] + }, d.draft_id)) + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-light d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted", + children: draftModalTab === 'DRAFT' ? `${draftBillsList.length} draft bill(s) pending` : `${draftBillsList.length} converted draft bill(s)` + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-secondary", + onClick: () => setShowDraftModal(false), + children: "Close" + })] + })] + }) + }) + })] + }); +} + +// ========================================================================= +// 1.5. INVOICES & SALES REGISTER (ALL INVOICES, SEARCHABLE, EDIT & REPRINT) +// ========================================================================= +function InvoicesView({ + store, + notify, + onEditInPos +}) { + if (!store) { + return /*#__PURE__*/_jsxs("div", { + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary me-2" + }), "Loading invoices register..."] + }); + } + const [invoices, setInvoices] = useState([]); + const [stats, setStats] = useState({ + today_count: 0, + today_amount: 0, + total_count: 0, + total_amount: 0, + total_returns: 0 + }); + const [pagination, setPagination] = useState({ + current_page: 1, + per_page: 25, + total_records: 0, + total_pages: 1 + }); + const [isLoading, setIsLoading] = useState(false); + + // Filters + const [searchQuery, setSearchQuery] = useState(''); + const [datePreset, setDatePreset] = useState('all'); // 'today', 'yesterday', 'last7', 'month', 'all' + const [fromDate, setFromDate] = useState(''); + const [toDate, setToDate] = useState(''); + const [paymentMode, setPaymentMode] = useState('ALL'); + const [page, setPage] = useState(1); + const [limit, setLimit] = useState(25); + + // Selected invoice for View/Print Drawer + const [viewInvoice, setViewInvoice] = useState(null); + const [isPrintOpen, setIsPrintOpen] = useState(false); + const [printFormat, setPrintFormat] = useState('thermal'); // 'thermal', 'a5', 'a4' + const [isLoadingView, setIsLoadingView] = useState(false); + + // Quick Edit Details Modal state + const [editModalSale, setEditModalSale] = useState(null); + const [editForm, setEditForm] = useState({ + patient_name: '', + patient_mobile: '', + patient_address: '', + age: '', + gender: '', + doctor_name: '', + doctor_reg_no: '', + payment_mode: 'Cash', + payment_reference: '', + bank_name: '', + upi_ref_no: '', + card_ref_no: '', + remarks: '' + }); + const [isUpdating, setIsUpdating] = useState(false); + const loadInvoices = async (targetPage = page, customSearch = searchQuery) => { + setIsLoading(true); + try { + const params = new URLSearchParams({ + store_id: store.store_id || 0, + search: customSearch !== undefined ? customSearch : searchQuery, + from_date: fromDate || '', + to_date: toDate || '', + payment_mode: paymentMode || 'ALL', + page: targetPage, + limit: limit + }); + const res = await fetch(API_BASE + 'sales/list?' + params.toString()); + const data = await res.json(); + if (data.status) { + setInvoices(data.sales || []); + if (data.stats) setStats(data.stats); + if (data.pagination) setPagination(data.pagination); + setPage(targetPage); + } else { + notify(data.message || 'Failed to load invoices.', 'error'); + } + } catch (e) { + notify('Error fetching sales list: ' + e.message, 'error'); + } finally { + setIsLoading(false); + } + }; + useEffect(() => { + loadInvoices(1); + }, [store?.store_id, fromDate, toDate, paymentMode, limit]); + const handleDatePreset = preset => { + setDatePreset(preset); + const today = new Date(); + const formatDate = d => d.toISOString().split('T')[0]; + if (preset === 'today') { + const todayStr = formatDate(today); + setFromDate(todayStr); + setToDate(todayStr); + } else if (preset === 'yesterday') { + const yest = new Date(today); + yest.setDate(yest.getDate() - 1); + const yestStr = formatDate(yest); + setFromDate(yestStr); + setToDate(yestStr); + } else if (preset === 'last7') { + const past7 = new Date(today); + past7.setDate(past7.getDate() - 7); + setFromDate(formatDate(past7)); + setToDate(formatDate(today)); + } else if (preset === 'month') { + const firstDay = new Date(today.getFullYear(), today.getMonth(), 1); + setFromDate(formatDate(firstDay)); + setToDate(formatDate(today)); + } else if (preset === 'all') { + setFromDate(''); + setToDate(''); + } + }; + const handleSearchSubmit = e => { + if (e) e.preventDefault(); + loadInvoices(1, searchQuery); + }; + const clearSearch = () => { + setSearchQuery(''); + loadInvoices(1, ''); + }; + + // Open View / Print Drawer + const openPrintDrawer = async saleId => { + setIsLoadingView(true); + try { + const res = await fetch(API_BASE + 'sales/invoice/' + saleId); + const data = await res.json(); + if (data.status) { + setViewInvoice(data); + setIsPrintOpen(true); + } else { + notify(data.message || 'Invoice details not found.', 'error'); + } + } catch (e) { + notify('Error loading invoice: ' + e.message, 'error'); + } finally { + setIsLoadingView(false); + } + }; + + // Open Edit Details Modal + const openEditModal = sale => { + setEditModalSale(sale); + setEditForm({ + patient_name: sale.patient_name || '', + patient_mobile: sale.patient_mobile || '', + patient_address: sale.patient_address || '', + age: sale.age || '', + gender: sale.gender || '', + doctor_name: sale.doctor_name || '', + doctor_reg_no: sale.doctor_reg_no || '', + payment_mode: sale.payment_mode || 'Cash', + payment_reference: sale.payment_reference || '', + bank_name: sale.bank_name || '', + upi_ref_no: sale.upi_ref_no || '', + card_ref_no: sale.card_ref_no || '', + remarks: sale.reconciled_notes || '' + }); + }; + const handleSaveEdit = async e => { + e.preventDefault(); + if (!editModalSale) return; + setIsUpdating(true); + try { + const res = await fetch(API_BASE + 'sales/update', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + sale_id: editModalSale.sale_id, + ...editForm + }) + }); + const data = await res.json(); + if (data.status) { + notify(`Invoice {editModalSale.invoice_no} updated successfully!`, 'success'); + setEditModalSale(null); + loadInvoices(page); + } else { + notify(data.message || 'Failed to update invoice.', 'error'); + } + } catch (err) { + notify('Error saving invoice update: ' + err.message, 'error'); + } finally { + setIsUpdating(false); + } + }; + + // Load into POS Counter Desk for direct re-billing / line items editing + const handleEditInPos = async saleId => { + setIsLoadingView(true); + try { + const res = await fetch(API_BASE + 'sales/invoice/' + saleId); + const data = await res.json(); + if (data.status && data.sale) { + if (onEditInPos) { + onEditInPos(data); + } + } else { + notify(data.message || 'Failed to load invoice for POS edit.', 'error'); + } + } catch (e) { + notify('Error: ' + e.message, 'error'); + } finally { + setIsLoadingView(false); + } + }; + const printThermalReceipt = () => { + if (!viewInvoice || !viewInvoice.sale) return; + const txt = generateThermalReceiptText(viewInvoice); + const win = window.open('', '_blank', 'width=420,height=650'); + if (!win) { + notify('Pop-up blocked. Please allow pop-ups to print thermal receipt.', 'warning'); + return; + } + try { + win.document.title = 'Thermal Receipt - ' + (viewInvoice.sale ? viewInvoice.sale.invoice_no : ''); + const style = win.document.createElement('style'); + style.textContent = '@page { size: 80mm auto; margin: 0; } html, body { margin: 0; padding: 0; background: #fff; } body { padding: 4mm 2mm; font-family: Courier, monospace; font-size: 11px; line-height: 1.25; color: #000; } pre { margin: 0; font-family: inherit; font-size: inherit; white-space: pre-wrap; word-break: break-all; }'; + win.document.head.appendChild(style); + const pre = win.document.createElement('pre'); + pre.textContent = txt; + win.document.body.appendChild(pre); + setTimeout(() => { + try { + win.focus(); + win.print(); + } catch (pe) { + console.error('Print trigger error', pe); + } + }, 350); + } catch (e) { + console.error('Error writing thermal window:', e); + } + }; + const printPdf = (format = 'a5') => { + if (!viewInvoice || !viewInvoice.sale) return; + const saleId = viewInvoice.sale.sale_id; + const url = `{API_BASE}sales/invoice-pdf/{saleId}?format={format}&view=1`; + const printWindow = window.open(url, '_blank'); + if (!printWindow) { + notify('Popup was blocked by browser. Please allow popups for PDF printing.', 'error'); + } + }; + const downloadPdf = (format = 'a5') => { + if (!viewInvoice || !viewInvoice.sale) return; + const saleId = viewInvoice.sale.sale_id; + const url = `{API_BASE}sales/invoice-pdf/{saleId}?format={format}&download=1`; + const a = document.createElement('a'); + a.href = url; + a.download = `Invoice_{viewInvoice.sale.invoice_no.replace(/[^a-zA-Z0-9_-]/g, '_')}_{format.toUpperCase()}.pdf`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + const generateThermalReceiptText = inv => { + if (!inv || !inv.sale) return ''; + const sale = inv.sale; + const items = inv.items || []; + const returnItems = inv.return_items || []; + const LINE_WIDTH = 48; + const padR = (str, len) => String(str || '').slice(0, len).padEnd(len, ' '); + const padL = (str, len) => String(str || '').slice(0, len).padStart(len, ' '); + const center = str => { + const s = String(str || '').trim(); + if (s.length >= LINE_WIDTH) return s.slice(0, LINE_WIDTH); + const pad = Math.floor((LINE_WIDTH - s.length) / 2); + return ' '.repeat(pad) + s; + }; + const rule = (char = '=') => char.repeat(LINE_WIDTH); + let lines = []; + lines.push(center(inv.store?.store_name || 'HOSPITAL PHARMACY')); + lines.push(center(`{inv.store?.building_name || 'Main Hospital'} - {inv.store?.floor_no || 'Ground Floor'}`)); + if (inv.store?.phone) lines.push(center(`Ph: {inv.store.phone}`)); + if (inv.store?.gstin) lines.push(center(`GSTIN: {inv.store.gstin}`)); + if (inv.store?.drug_license_no_20b) lines.push(center(`DL: {inv.store.drug_license_no_20b} / {inv.store?.drug_license_no_21b || ''}`)); + lines.push(rule('=')); + lines.push(center('TAX INVOICE / CASH MEMO')); + lines.push(rule('-')); + lines.push(padR(`Inv No : {sale.invoice_no}`, 28) + padL(`Date: {String(sale.sale_date).slice(0, 10)}`, 20)); + lines.push(padR(`Patient: {sale.patient_name || 'Walk-in Customer'}`, 32) + padL(sale.uhid ? `UHID: {sale.uhid}` : '', 16)); + if (sale.doctor_name) lines.push(`Doctor : {sale.doctor_name}`); + lines.push(rule('-')); + lines.push(padR('ITEM', 22) + padR('BATCH', 8) + padL('QTY', 5) + padL('RATE', 6) + padL('TOTAL', 7)); + lines.push(rule('-')); + items.forEach(it => { + const name = (it.item_name || 'Item').slice(0, 21); + const batch = (it.batch_no || '').slice(0, 7); + const qty = String(it.qty || 1); + const rate = Number(it.unit_price || it.effective_rate || 0).toFixed(2); + const total = Number(it.total_amount || 0).toFixed(2); + lines.push(padR(name, 22) + padR(batch, 8) + padL(qty, 5) + padL(rate, 6) + padL(total, 7)); + }); + if (returnItems.length > 0) { + lines.push(rule('-')); + lines.push(center('RETURNED / EXCHANGED ITEMS')); + returnItems.forEach(it => { + const name = ('RET: ' + (it.item_name || 'Item')).slice(0, 21); + const batch = (it.batch_no || '').slice(0, 7); + const qty = String(it.qty || 1); + const rate = Number(it.unit_price || 0).toFixed(2); + const total = '-' + Number(it.total_amount || 0).toFixed(2); + lines.push(padR(name, 22) + padR(batch, 8) + padL(qty, 5) + padL(rate, 6) + padL(total, 7)); + }); + } + lines.push(rule('=')); + lines.push(padR('Gross Total:', 36) + padL(`Rs. {Number(sale.gross_amount).toFixed(2)}`, 12)); + if (Number(sale.discount_amount) > 0) { + lines.push(padR('Discount Allowed:', 36) + padL(`-Rs. {Number(sale.discount_amount).toFixed(2)}`, 12)); + } + if (Number(sale.return_amount) > 0) { + lines.push(padR('Less Return Value:', 36) + padL(`-Rs. {Number(sale.return_amount).toFixed(2)}`, 12)); + } + lines.push(padR('NET AMOUNT PAYABLE:', 34) + padL(`Rs. {Number(sale.net_amount).toFixed(2)}`, 14)); + lines.push(rule('-')); + lines.push(padR(`Paid by: {sale.payment_mode || 'Cash'}`, 30) + padL(`Status: PAID`, 18)); + lines.push(rule('=')); + lines.push(center('Thank you for your visit! Get well soon!')); + lines.push(center('Medicines cannot be returned without original bill.')); + return lines.join('n'); + }; + return /*#__PURE__*/_jsxs("div", { + className: "invoices-view-wrapper", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "mb-0 fw-bold text-dark d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt-cutoff text-primary fs-4" + }), "Invoices & Sales Register", /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle fs-6 rounded-pill px-2.5 py-0.5", + children: [pagination.total_records || 0, " Bills"] + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-secondary", + children: ["Showing all sales across pharmacy desk ordered ", /*#__PURE__*/_jsx("strong", { + children: "Latest to Oldest" + }), ". Search by bill #, patient, mobile, or doctor."] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary d-inline-flex align-items-center gap-1.5", + onClick: () => loadInvoices(page), + disabled: isLoading, + children: [/*#__PURE__*/_jsx("i", { + className: `bi bi-arrow-clockwise {isLoading ? 'spin' : ''}` + }), "Refresh"] + }), onEditInPos && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-primary-custom d-inline-flex align-items-center gap-1.5", + onClick: () => onEditInPos(null), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-plus-fill" + }), "New POS Counter Bill"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center gap-2 mb-3 bg-light p-2.5 rounded-3 border", + children: [/*#__PURE__*/_jsxs("span", { + className: "text-muted small fw-bold me-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar3 me-1" + }), " Quick Filter:"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `invoices-date-pill {datePreset === 'today' ? 'active' : ''}`, + onClick: () => handleDatePreset('today'), + children: "Today" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `invoices-date-pill {datePreset === 'yesterday' ? 'active' : ''}`, + onClick: () => handleDatePreset('yesterday'), + children: "Yesterday" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `invoices-date-pill {datePreset === 'last7' ? 'active' : ''}`, + onClick: () => handleDatePreset('last7'), + children: "Last 7 Days" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `invoices-date-pill {datePreset === 'month' ? 'active' : ''}`, + onClick: () => handleDatePreset('month'), + children: "This Month" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: `invoices-date-pill {datePreset === 'all' ? 'active' : ''}`, + onClick: () => handleDatePreset('all'), + children: "All Records" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-6 col-md-3", + children: /*#__PURE__*/_jsxs("div", { + className: "invoices-stats-card border-start border-primary border-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-secondary small fw-bold text-uppercase", + children: "Today's Bills" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-check text-primary fs-5" + })] + }), /*#__PURE__*/_jsx("h4", { + className: "fw-bold text-dark mb-0", + children: stats.today_count || 0 + }), /*#__PURE__*/_jsxs("small", { + className: "text-primary fw-semibold", + children: ["₹", Number(stats.today_amount || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6 col-md-3", + children: /*#__PURE__*/_jsxs("div", { + className: "invoices-stats-card border-start border-success border-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-secondary small fw-bold text-uppercase", + children: "Total Invoices" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-receipt text-success fs-5" + })] + }), /*#__PURE__*/_jsx("h4", { + className: "fw-bold text-dark mb-0", + children: stats.total_count || 0 + }), /*#__PURE__*/_jsxs("small", { + className: "text-success fw-semibold", + children: ["₹", Number(stats.total_amount || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6 col-md-3", + children: /*#__PURE__*/_jsxs("div", { + className: "invoices-stats-card border-start border-warning border-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-secondary small fw-bold text-uppercase", + children: "Returns / Refunds" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left text-warning fs-5" + })] + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-dark mb-0", + children: ["₹", Number(stats.total_returns || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Total customer returns" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6 col-md-3", + children: /*#__PURE__*/_jsxs("div", { + className: "invoices-stats-card border-start border-info border-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-secondary small fw-bold text-uppercase", + children: "Net Realized" + }), /*#__PURE__*/_jsx("i", { + className: "bi bi-cash-stack text-info fs-5" + })] + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-dark mb-0", + children: ["₹", Number((stats.total_amount || 0) - (stats.total_returns || 0)).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-info fw-semibold", + children: "Net pharmacy collection" + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "card border shadow-sm mb-3", + children: /*#__PURE__*/_jsx("div", { + className: "card-body p-3", + children: /*#__PURE__*/_jsxs("form", { + onSubmit: handleSearchSubmit, + className: "row g-2 align-items-center", + children: [/*#__PURE__*/_jsx("div", { + className: "col-12 col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white text-muted", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "Search Bill #, Patient, Mobile, Doctor...", + value: searchQuery, + onChange: e => setSearchQuery(e.target.value) + }), searchQuery && /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary", + onClick: clearSearch, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-primary px-3", + children: "Search" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6 col-md-2", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light text-muted", + style: { + fontSize: '0.72rem' + }, + children: "From" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control", + value: fromDate, + onChange: e => { + setFromDate(e.target.value); + setDatePreset('custom'); + } + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6 col-md-2", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light text-muted", + style: { + fontSize: '0.72rem' + }, + children: "To" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control", + value: toDate, + onChange: e => { + setToDate(e.target.value); + setDatePreset('custom'); + } + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6 col-md-2", + children: /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: paymentMode, + onChange: e => setPaymentMode(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "ALL", + children: "All Payments" + }), /*#__PURE__*/_jsx("option", { + value: "Cash", + children: "Cash" + }), /*#__PURE__*/_jsx("option", { + value: "UPI", + children: "UPI / QR" + }), /*#__PURE__*/_jsx("option", { + value: "Card", + children: "Card" + }), /*#__PURE__*/_jsx("option", { + value: "Mixed", + children: "Split / Mixed" + }), /*#__PURE__*/_jsx("option", { + value: "IPD_Credit", + children: "IPD Credit" + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-2 d-flex justify-content-end align-items-center gap-2", + children: [/*#__PURE__*/_jsx("label", { + className: "text-muted small mb-0", + children: "Show:" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + style: { + width: 80 + }, + value: limit, + onChange: e => setLimit(Number(e.target.value)), + children: [/*#__PURE__*/_jsx("option", { + value: "15", + children: "15" + }), /*#__PURE__*/_jsx("option", { + value: "25", + children: "25" + }), /*#__PURE__*/_jsx("option", { + value: "50", + children: "50" + }), /*#__PURE__*/_jsx("option", { + value: "100", + children: "100" + })] + })] + })] + }) + }) + }), /*#__PURE__*/_jsxs("div", { + className: "card border shadow-sm mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover align-middle mb-0 invoices-table", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 140 + }, + children: "Invoice No" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 130 + }, + children: "Date & Time" + }), /*#__PURE__*/_jsx("th", { + children: "Patient Details" + }), /*#__PURE__*/_jsx("th", { + children: "Doctor" + }), /*#__PURE__*/_jsx("th", { + children: "Items Dispensed" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 100 + }, + children: "Payment" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 110 + }, + children: "Net Total" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 90 + }, + children: "Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 220 + }, + children: "Actions" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: isLoading ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "9", + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary me-2" + }), "Loading invoices..."] + }) + }) : invoices.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "9", + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-inbox fs-2 d-block mb-2 text-secondary" + }), /*#__PURE__*/_jsx("h6", { + children: "No invoices found" + }), /*#__PURE__*/_jsx("p", { + className: "small mb-0", + children: "Try changing your search query or date range filters." + })] + }) + }) : invoices.map(inv => { + const hasReturns = Number(inv.return_amount) > 0; + return /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-dark-subtle text-dark border font-monospace px-2 py-1 fs-6 cursor-pointer", + onClick: () => openPrintDrawer(inv.sale_id), + title: "Click to View / Print Invoice", + style: { + cursor: 'pointer' + }, + children: inv.invoice_no + }), inv.abdm_care_context_ref && /*#__PURE__*/_jsxs("span", { + className: "d-block mt-1 text-success", + style: { + fontSize: '0.68rem' + }, + title: "ABDM Linked", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-fill-check me-0.5" + }), " ABDM"] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold text-dark", + style: { + fontSize: '0.82rem' + }, + children: String(inv.sale_date).slice(0, 10) + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: String(inv.sale_date).slice(11, 16) + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: inv.patient_name || 'Walk-in Customer' + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1 flex-wrap mt-0.5", + children: [inv.uhid && /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-primary border", + style: { + fontSize: '0.68rem' + }, + children: inv.uhid + }), inv.patient_mobile && /*#__PURE__*/_jsxs("span", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-0.5" + }), " ", inv.patient_mobile] + }), /*#__PURE__*/_jsx("span", { + className: `badge {inv.patient_type === 'IPD' ? 'bg-danger-subtle text-danger' : (inv.patient_type === 'OPD' ? 'bg-primary-subtle text-primary' : 'bg-secondary-subtle text-secondary')}`, + style: { + fontSize: '0.65rem' + }, + children: inv.patient_type || 'Walk-in' + })] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "text-dark fw-medium", + style: { + fontSize: '0.82rem' + }, + children: inv.doctor_name || 'Self / Walk-in' + }), inv.doctor_reg_no && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + style: { + fontSize: '0.7rem' + }, + children: ["Reg: ", inv.doctor_reg_no] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center gap-1 mb-0.5", + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-info-subtle text-info border border-info-subtle", + style: { + fontSize: '0.7rem' + }, + children: [inv.items_count || 0, " items"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "text-secondary text-truncate", + style: { + maxWidth: 220, + fontSize: '0.75rem' + }, + title: inv.items_summary, + children: inv.items_summary || 'N/A' + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge {inv.payment_mode === 'Cash' ? 'bg-success-subtle text-success border border-success-subtle' : (inv.payment_mode === 'UPI' ? 'bg-info-subtle text-info border border-info-subtle' : (inv.payment_mode === 'Card' ? 'bg-primary-subtle text-primary border border-primary-subtle' : 'bg-warning-subtle text-warning-emphasis border border-warning-subtle'))}`, + children: inv.payment_mode || 'Cash' + }) + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark fs-6", + children: ["₹", Number(inv.net_amount).toFixed(2)] + }), Number(inv.discount_amount) > 0 && /*#__PURE__*/_jsxs("small", { + className: "text-danger d-block", + style: { + fontSize: '0.7rem' + }, + children: ["Disc: -₹", Number(inv.discount_amount).toFixed(2)] + }), hasReturns && /*#__PURE__*/_jsxs("small", { + className: "text-warning-emphasis d-block", + style: { + fontSize: '0.7rem' + }, + children: ["Ret: -₹", Number(inv.return_amount).toFixed(2)] + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: hasReturns ? /*#__PURE__*/_jsx("span", { + className: "badge bg-warning text-dark", + style: { + fontSize: '0.7rem' + }, + children: "Exchange" + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-success-subtle text-success border border-success-subtle", + style: { + fontSize: '0.7rem' + }, + children: "Paid" + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-center gap-1", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-primary py-1 px-2 d-inline-flex align-items-center gap-1", + onClick: () => openPrintDrawer(inv.sale_id), + title: "View & Print Invoice (Thermal, A5 Landscape, A4)", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer" + }), /*#__PURE__*/_jsx("span", { + children: "View" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-secondary py-1 px-2 d-inline-flex align-items-center gap-1", + onClick: () => openEditModal(inv), + title: "Quick Edit Patient Name, Mobile, Doctor, Payment Mode", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil" + }), /*#__PURE__*/_jsx("span", { + children: "Edit" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-success py-1 px-2 d-inline-flex align-items-center gap-1", + onClick: () => handleEditInPos(inv.sale_id), + title: "Open in POS Counter Desk to edit medicines, quantities, or re-bill", + style: { + fontSize: '0.72rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart3" + }), /*#__PURE__*/_jsx("span", { + children: "Edit in POS" + })] + })] + }) + })] + }, inv.sale_id); + }) + })] + }) + }), pagination.total_pages > 1 && /*#__PURE__*/_jsxs("div", { + className: "card-footer bg-white d-flex flex-wrap justify-content-between align-items-center py-2 px-3", + children: [/*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: ["Showing page ", /*#__PURE__*/_jsx("strong", { + children: pagination.current_page + }), " of ", /*#__PURE__*/_jsx("strong", { + children: pagination.total_pages + }), " (", pagination.total_records, " total invoices)"] + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-secondary", + disabled: pagination.current_page <= 1 || isLoading, + onClick: () => loadInvoices(pagination.current_page - 1), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-chevron-left" + }), " Prev"] + }), /*#__PURE__*/_jsxs("span", { + className: "btn btn-outline-secondary disabled fw-bold text-dark px-3", + children: [pagination.current_page, " / ", pagination.total_pages] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-secondary", + disabled: pagination.current_page >= pagination.total_pages || isLoading, + onClick: () => loadInvoices(pagination.current_page + 1), + children: ["Next ", /*#__PURE__*/_jsx("i", { + className: "bi bi-chevron-right" + })] + })] + })] + })] + }), editModalSale && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.65)', + backdropFilter: 'blur(3px)', + zIndex: 1060 + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg rounded-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title mb-0 fw-bold d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square text-warning" + }), "Edit Invoice Details: ", /*#__PURE__*/_jsx("span", { + className: "text-info", + children: editModalSale.invoice_no + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setEditModalSale(null) + })] + }), /*#__PURE__*/_jsxs("form", { + onSubmit: handleSaveEdit, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "alert alert-info py-1.5 px-2.5 mb-3", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-info-circle me-1" + }), "Use this to correct patient information, doctor name, or payment mode on this completed bill. To modify medicine quantities or items, click ", /*#__PURE__*/_jsx("strong", { + children: "\"Edit in POS\"" + }), " in the main table."] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Patient Name" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.patient_name, + onChange: e => setEditForm({ + ...editForm, + patient_name: e.target.value + }), + required: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Mobile Number" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.patient_mobile, + onChange: e => setEditForm({ + ...editForm, + patient_mobile: e.target.value + }), + placeholder: "10-digit mobile" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Age" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.age, + onChange: e => setEditForm({ + ...editForm, + age: e.target.value + }), + placeholder: "e.g. 45 Y" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Gender" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: editForm.gender, + onChange: e => setEditForm({ + ...editForm, + gender: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "Select Gender" + }), /*#__PURE__*/_jsx("option", { + value: "Male", + children: "Male" + }), /*#__PURE__*/_jsx("option", { + value: "Female", + children: "Female" + }), /*#__PURE__*/_jsx("option", { + value: "Other", + children: "Other" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Payment Mode" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: editForm.payment_mode, + onChange: e => setEditForm({ + ...editForm, + payment_mode: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "Cash", + children: "Cash" + }), /*#__PURE__*/_jsx("option", { + value: "UPI", + children: "UPI / QR" + }), /*#__PURE__*/_jsx("option", { + value: "Card", + children: "Card" + }), /*#__PURE__*/_jsx("option", { + value: "Mixed", + children: "Mixed / Split" + }), /*#__PURE__*/_jsx("option", { + value: "IPD_Credit", + children: "IPD Credit" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Doctor Name" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.doctor_name, + onChange: e => setEditForm({ + ...editForm, + doctor_name: e.target.value + }), + placeholder: "Prescribing doctor" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Doctor Reg No" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.doctor_reg_no, + onChange: e => setEditForm({ + ...editForm, + doctor_reg_no: e.target.value + }), + placeholder: "MCI / State Medical Council Reg No" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Patient Address" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.patient_address, + onChange: e => setEditForm({ + ...editForm, + patient_address: e.target.value + }), + placeholder: "Address / City" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Payment Ref / UPI UTR / Bank" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.payment_reference || editForm.upi_ref_no || editForm.card_ref_no, + onChange: e => setEditForm({ + ...editForm, + payment_reference: e.target.value, + upi_ref_no: e.target.value + }), + placeholder: "Transaction reference ID" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Audit Notes / Remarks" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: editForm.remarks, + onChange: e => setEditForm({ + ...editForm, + remarks: e.target.value + }), + placeholder: "Reason for correction or cashier notes" + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer bg-light py-2 px-3 d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setEditModalSale(null), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-sm btn-primary px-3 fw-bold", + disabled: isUpdating, + children: isUpdating ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split me-1" + }), " Saving..."] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle me-1" + }), " Save Changes"] + }) + })] + })] + })] + }) + }) + }), /*#__PURE__*/_jsx("div", { + className: `print-drawer-overlay {isPrintOpen ? 'open' : ''}`, + onClick: () => setIsPrintOpen(false) + }), /*#__PURE__*/_jsx("div", { + className: `print-drawer {isPrintOpen ? 'open' : ''}`, + id: "invoices-print-drawer", + children: viewInvoice && /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("div", { + className: "print-drawer-header", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt text-warning fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold text-white", + children: "Invoice & Print Desk" + }), /*#__PURE__*/_jsxs("small", { + className: "text-secondary", + style: { + fontSize: '0.72rem' + }, + children: ["Bill: ", /*#__PURE__*/_jsx("span", { + className: "text-info fw-bold", + children: viewInvoice.sale.invoice_no + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1.5 flex-wrap", + children: [/*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-xs py-1 px-2 {printFormat === 'thermal' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setPrintFormat('thermal'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt me-1" + }), " Thermal (Text)"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-xs py-1 px-2 {printFormat === 'a5' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setPrintFormat('a5'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf me-1" + }), " A5 Landscape (PDF)"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-xs py-1 px-2 {printFormat === 'a4' ? 'btn-warning text-dark fw-bold' : 'btn-outline-light text-white'}`, + style: { + fontSize: '0.72rem' + }, + onClick: () => setPrintFormat('a4'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf me-1" + }), " A4 (PDF)"] + })] + }), printFormat === 'thermal' ? /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-warning text-dark fw-bold py-1 px-2.5 ms-0.5", + onClick: printThermalReceipt, + title: "Print on 80mm Thermal Receipt Printer", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer-fill me-1" + }), " Print Thermal"] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-light py-1 px-2 text-white", + onClick: () => downloadPdf(printFormat), + title: "Download PDF Document", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1 text-info" + }), " PDF"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-primary py-1 px-2.5 ms-0.5 fw-bold", + onClick: () => printPdf(printFormat), + title: "Print Clean Vector PDF", + style: { + fontSize: '0.75rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF (", printFormat === 'a5' ? 'A5 LANDSCAPE' : printFormat.toUpperCase(), ")"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-light rounded-pill px-2.5 py-1 ms-1 d-flex align-items-center gap-1", + onClick: () => setIsPrintOpen(false), + title: "Close Print Drawer (Esc)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-lg" + }), /*#__PURE__*/_jsx("kbd", { + style: { + background: '#334155', + color: '#f8fafc', + fontSize: '0.62rem', + padding: '1px 3px', + borderRadius: '3px' + }, + children: "Esc" + })] + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "print-drawer-body", + children: /*#__PURE__*/_jsx("div", { + className: "print-paper-card", + children: /*#__PURE__*/_jsxs("div", { + id: "printable-container", + children: [printFormat === 'thermal' && /*#__PURE__*/_jsxs("div", { + className: "p-2 text-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2 px-2 pb-2 border-bottom", + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: "Thermal 80mm ESC/POS Text" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-warning text-dark fw-bold", + onClick: printThermalReceipt, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer-fill me-1" + }), " Print Thermal Receipt"] + })] + }), /*#__PURE__*/_jsx("pre", { + style: { + fontFamily: '"Courier New", Courier, monospace', + fontSize: '12px', + lineHeight: '1.2', + color: '#000000', + backgroundColor: '#ffffff', + padding: '12px', + margin: '0 auto', + maxWidth: '380px', + textAlign: 'left', + whiteSpace: 'pre-wrap', + wordBreak: 'break-word', + border: '1px dashed #cbd5e1', + borderRadius: '6px' + }, + children: generateThermalReceiptText(viewInvoice) + })] + }), printFormat === 'a5' && /*#__PURE__*/_jsxs("div", { + className: "p-3 text-center print-a5-invoice", + style: { + maxWidth: '820px', + margin: '0 auto' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "alert alert-info py-1.5 px-3 mb-3 d-flex justify-content-between align-items-center shadow-sm", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf-fill me-1" + }), /*#__PURE__*/_jsx("strong", { + children: "A5 Landscape PDF (210mm × 148mm):" + }), " Native vector document rendered by mPDF."] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1.5", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-outline-primary py-1 px-2", + onClick: () => downloadPdf('a5'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1" + }), " Download"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-primary py-1 px-2.5 fw-bold", + onClick: () => printPdf('a5'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF (A5 Landscape)"] + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "border rounded shadow-sm overflow-hidden", + style: { + background: '#525659', + padding: '12px' + }, + children: /*#__PURE__*/_jsx("iframe", { + src: `{API_BASE}sales/invoice-pdf/{viewInvoice.sale.sale_id}?format=a5&view=1`, + title: "A5 Landscape PDF Preview", + style: { + width: '100%', + height: '540px', + border: 'none', + borderRadius: '4px', + background: '#ffffff' + } + }) + })] + }), printFormat === 'a4' && /*#__PURE__*/_jsxs("div", { + className: "p-3 text-center print-a4-invoice", + style: { + maxWidth: '780px', + margin: '0 auto' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "alert alert-info py-1.5 px-3 mb-3 d-flex justify-content-between align-items-center shadow-sm", + style: { + fontSize: '0.78rem' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-pdf-fill me-1" + }), /*#__PURE__*/_jsx("strong", { + children: "A4 Vector PDF (210mm × 297mm):" + }), " Native vector document rendered by mPDF."] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1.5", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-outline-primary py-1 px-2", + onClick: () => downloadPdf('a4'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-download me-1" + }), " Download"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-primary py-1 px-2.5 fw-bold", + onClick: () => printPdf('a4'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PDF (A4)"] + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "border rounded shadow-sm overflow-hidden", + style: { + background: '#525659', + padding: '12px' + }, + children: /*#__PURE__*/_jsx("iframe", { + src: `{API_BASE}sales/invoice-pdf/{viewInvoice.sale.sale_id}?format=a4&view=1`, + title: "A4 PDF Preview", + style: { + width: '100%', + height: '620px', + border: 'none', + borderRadius: '4px', + background: '#ffffff' + } + }) + })] + })] + }) + }) + })] + }) + })] + }); +} + +// ========================================================================= +// 2. LIVE INVENTORY & BATCH MATRIX VIEW +// ========================================================================= +function InventoryView({ + store, + notify, + activeOperator +}) { + if (!store) return null; + const [invSubTab, setInvSubTab] = useState('live'); // 'live', 'physical_audit', 'audit_logs' + const [stock, setStock] = useState([]); + const [summary, setSummary] = useState({}); + const [filter, setFilter] = useState('all'); + const [searchTerm, setSearchTerm] = useState(''); + const [loading, setLoading] = useState(false); + + // Single Batch Quick Reconcile Modal State + const [reconcileModalItem, setReconcileModalItem] = useState(null); + const [reconcilePhysicalQty, setReconcilePhysicalQty] = useState(''); + const [reconcileAuditType, setReconcileAuditType] = useState('PHYSICAL_VARIATION'); + const [reconcileRemarks, setReconcileRemarks] = useState(''); + const [isSubmittingReconcile, setIsSubmittingReconcile] = useState(false); + + // Cycle Count Audit Sheet State + const [cycleRackFilter, setCycleRackFilter] = useState('all'); + const [cycleSearch, setCycleSearch] = useState(''); + const [cycleCounts, setCycleCounts] = useState({}); // { [batch_id]: { physical_qty, audit_type, remarks } } + const [isCommittingCycle, setIsCommittingCycle] = useState(false); + + // Audit Log History State + const [auditLogs, setAuditLogs] = useState([]); + const [auditTotal, setAuditTotal] = useState(0); + const [auditFilterType, setAuditFilterType] = useState('all'); + const [auditSearch, setAuditSearch] = useState(''); + const [auditFromDate, setAuditFromDate] = useState(''); + const [auditToDate, setAuditToDate] = useState(''); + const [loadingAuditLogs, setLoadingAuditLogs] = useState(false); + useEffect(() => { + if (store?.store_id) { + loadStock(); + } + }, [store?.store_id, filter]); + useEffect(() => { + if (invSubTab === 'audit_logs' && store?.store_id) { + loadAuditLogs(); + } + }, [invSubTab, store?.store_id, auditFilterType, auditFromDate, auditToDate]); + const loadStock = async () => { + setLoading(true); + try { + const res = await fetch(API_BASE + `stock/list?store_id=${store.store_id}&filter=${filter}`); + const data = await res.json(); + if (data.status) { + setStock(data.stock || []); + setSummary(data.summary || {}); + } + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }; + const loadAuditLogs = async () => { + setLoadingAuditLogs(true); + try { + let url = `${API_BASE}stock/audit-list?store_id=${store.store_id}&limit=100`; + if (auditFilterType !== 'all') url += `&audit_type=${encodeURIComponent(auditFilterType)}`; + if (auditSearch.trim()) url += `&search=${encodeURIComponent(auditSearch.trim())}`; + if (auditFromDate) url += `&from_date=${auditFromDate}`; + if (auditToDate) url += `&to_date=${auditToDate}`; + const res = await fetch(url); + const data = await res.json(); + if (data.status) { + setAuditLogs(data.logs || []); + setAuditTotal(data.total || 0); + } + } catch (e) { + console.error("Failed to load audit logs:", e); + } finally { + setLoadingAuditLogs(false); + } + }; + + // Open Single Reconcile Modal + const openReconcileModal = item => { + setReconcileModalItem(item); + setReconcilePhysicalQty(item.current_qty !== undefined ? item.current_qty : ''); + setReconcileAuditType('PHYSICAL_VARIATION'); + setReconcileRemarks(''); + }; + + // Submit Single Reconcile + const handleReconcileSubmit = async () => { + if (!reconcileModalItem) return; + const pQty = Number(reconcilePhysicalQty); + if (isNaN(pQty) || pQty < 0) { + notify('Please enter a valid physical count (0 or greater).', 'error'); + return; + } + setIsSubmittingReconcile(true); + try { + const res = await fetch(API_BASE + 'stock/reconcile', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + item_id: reconcileModalItem.item_id, + batch_id: reconcileModalItem.batch_id, + physical_qty: pQty, + audit_type: reconcileAuditType, + remarks: reconcileRemarks.trim() || `Physical audit: System ${reconcileModalItem.current_qty} -> Physical ${pQty}`, + operator_id: activeOperator?.user_id || 1, + operator_name: activeOperator?.full_name || 'Staff' + }) + }); + const data = await res.json(); + if (data.status) { + const diffMsg = data.variation_qty === 0 ? 'Counts verified (0 discrepancy).' : data.variation_qty < 0 ? `Shortage adjusted: ${Math.abs(data.variation_qty)} units (Loss: ₹${data.variation_val})` : `Surplus added: +${data.variation_qty} units (₹${data.variation_val})`; + notify(`Stock reconciled! ${diffMsg}`, 'success'); + setReconcileModalItem(null); + loadStock(); + } else { + notify(data.message || 'Failed to reconcile stock.', 'error'); + } + } catch (e) { + notify('Network error during reconciliation.', 'error'); + } finally { + setIsSubmittingReconcile(false); + } + }; + + // Cycle Count Handler + const handleCycleCountChange = (batchId, val) => { + setCycleCounts(prev => ({ + ...prev, + [batchId]: { + ...(prev[batchId] || {}), + physical_qty: val + } + })); + }; + const handleCycleReasonChange = (batchId, reason) => { + setCycleCounts(prev => ({ + ...prev, + [batchId]: { + ...(prev[batchId] || {}), + audit_type: reason + } + })); + }; + const handleCycleRemarksChange = (batchId, remarks) => { + setCycleCounts(prev => ({ + ...prev, + [batchId]: { + ...(prev[batchId] || {}), + remarks: remarks + } + })); + }; + + // Submit Batch Cycle Count + const handleCommitCycleAudit = async () => { + const changedCounts = []; + for (const [bId, data] of Object.entries(cycleCounts)) { + if (data && data.physical_qty !== undefined && data.physical_qty !== '') { + const bItem = stock.find(s => s.batch_id == bId); + if (bItem) { + const pQty = Number(data.physical_qty); + const sQty = Number(bItem.current_qty); + if (!isNaN(pQty) && pQty >= 0 && (pQty !== sQty || data.force_log)) { + changedCounts.push({ + item_id: bItem.item_id, + batch_id: Number(bId), + physical_qty: pQty, + audit_type: data.audit_type || 'PHYSICAL_VARIATION', + remarks: data.remarks || `Cycle Count Audit: System ${sQty} -> Physical ${pQty}` + }); + } + } + } + } + if (changedCounts.length === 0) { + notify('No stock count adjustments detected in the cycle sheet.', 'warning'); + return; + } + setIsCommittingCycle(true); + try { + const res = await fetch(API_BASE + 'stock/batch-reconcile', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + counts: changedCounts, + operator_id: activeOperator?.user_id || 1, + operator_name: activeOperator?.full_name || 'Auditor', + remarks: `Routine Shelf Cycle Audit by ${activeOperator?.full_name || 'Auditor'}` + }) + }); + const data = await res.json(); + if (data.status) { + notify(`Cycle audit committed: ${data.reconciled_count} batches reconciled (Discrepancy: ₹${data.total_value})!`, 'success'); + setCycleCounts({}); + loadStock(); + } else { + notify(data.message || 'Failed to commit batch audit.', 'error'); + } + } catch (e) { + notify('Network error during batch reconciliation.', 'error'); + } finally { + setIsCommittingCycle(false); + } + }; + + // Extract unique racks/shelves from stock list + const uniqueRacks = [...new Set(stock.map(s => s.rack_no).filter(Boolean))]; + + // Filter stock for Live View + const filteredStock = stock.filter(s => s.item_name.toLowerCase().includes(searchTerm.toLowerCase()) || s.generic_name && s.generic_name.toLowerCase().includes(searchTerm.toLowerCase()) || s.batch_no.toLowerCase().includes(searchTerm.toLowerCase())); + + // Filter stock for Cycle Audit View + const cycleFilteredStock = stock.filter(s => { + const matchesRack = cycleRackFilter === 'all' || s.rack_no === cycleRackFilter; + const matchesSearch = !cycleSearch.trim() || s.item_name.toLowerCase().includes(cycleSearch.toLowerCase()) || s.generic_name && s.generic_name.toLowerCase().includes(cycleSearch.toLowerCase()) || s.batch_no.toLowerCase().includes(cycleSearch.toLowerCase()) || s.shelf_no && s.shelf_no.toLowerCase().includes(cycleSearch.toLowerCase()); + return matchesRack && matchesSearch; + }); + + // Summary of discrepancies in cycle sheet + let cycleDiscrepancyCount = 0; + let cycleDiscrepancyValue = 0; + for (const item of cycleFilteredStock) { + const cntData = cycleCounts[item.batch_id]; + if (cntData && cntData.physical_qty !== undefined && cntData.physical_qty !== '') { + const p = Number(cntData.physical_qty); + const s = Number(item.current_qty); + if (!isNaN(p) && p !== s) { + cycleDiscrepancyCount++; + const rate = Number(item.ptr || item.mrp || 0); + cycleDiscrepancyValue += Math.abs(p - s) * rate; + } + } + } + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3 pb-2 border-bottom", + children: [/*#__PURE__*/_jsxs("div", { + className: "btn-group shadow-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-sm fw-bold d-flex align-items-center gap-1.5 ${invSubTab === 'live' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setInvSubTab('live'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-boxes" + }), " Live Stock & Batches"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm fw-bold d-flex align-items-center gap-1.5 ${invSubTab === 'physical_audit' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setInvSubTab('physical_audit'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clipboard-check-fill" + }), " Physical Stock Take & Cycle Audit"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm fw-bold d-flex align-items-center gap-1.5 ${invSubTab === 'audit_logs' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => { + setInvSubTab('audit_logs'); + loadAuditLogs(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-check" + }), " Stock Discrepancy Audit Log"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center gap-2", + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border px-2.5 py-1.5 rounded-pill shadow-xs d-flex align-items-center gap-1.5", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge-fill text-primary" + }), /*#__PURE__*/_jsxs("span", { + children: ["Auditor: ", /*#__PURE__*/_jsx("strong", { + className: "text-dark", + children: activeOperator ? activeOperator.full_name : 'Store Staff' + })] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-primary-subtle text-primary", + style: { + fontSize: '0.65rem' + }, + children: activeOperator ? activeOperator.user_role.toUpperCase() : 'COUNTER' + })] + }) + })] + }), invSubTab === 'live' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-primary", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold text-uppercase", + children: "Total Batches in Store" + }), /*#__PURE__*/_jsx("h4", { + className: "fw-bolder text-dark mt-1 mb-0", + children: summary.total_rows || 0 + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-success", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold text-uppercase", + children: "Stock Cost Valuation (PTR)" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-success mt-1 mb-0", + children: ["₹", (summary.total_cost_valuation || 0).toLocaleString('en-IN')] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-warning", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold text-uppercase", + children: "Stock Retail Valuation (MRP)" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-dark mt-1 mb-0", + children: ["₹", (summary.total_mrp_valuation || 0).toLocaleString('en-IN')] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-info", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold text-uppercase", + children: "Counter / URL" + }), /*#__PURE__*/_jsxs("h6", { + className: "fw-bolder text-primary mt-1 mb-0 text-truncate", + children: ["MedicalStore/", store.store_slug] + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsx("button", { + className: `btn ${filter === 'all' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setFilter('all'), + children: "All Stock" + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${filter === 'low' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setFilter('low'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-down-circle me-1" + }), " Low Stock"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${filter === 'near_expiry' ? 'btn-warning' : 'btn-outline-secondary'}`, + onClick: () => setFilter('near_expiry'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1" + }), " Near Expiry (<90 Days)"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${filter === 'expired' ? 'btn-danger' : 'btn-outline-secondary'}`, + onClick: () => setFilter('expired'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-x me-1" + }), " Expired Stock"] + })] + }), /*#__PURE__*/_jsx("div", { + style: { + maxWidth: 320 + }, + className: "w-100", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "Search item, molecule, batch...", + value: searchTerm, + onChange: e => setSearchTerm(e.target.value) + })] + }) + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-0 overflow-hidden shadow-sm", + children: /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos table-hover align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Item & Generic Molecule" + }), /*#__PURE__*/_jsx("th", { + children: "Category" + }), /*#__PURE__*/_jsx("th", { + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + children: "Location" + }), /*#__PURE__*/_jsx("th", { + children: "Expiry" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "System Qty" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "PTR (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "MRP (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Valuation (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: loading ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "12", + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split fs-3 d-block mb-2 text-primary" + }), " Loading inventory batches..."] + }) + }) : filteredStock.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "12", + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-inboxes fs-3 d-block mb-1 text-secondary" + }), "No stock records found matching filters."] + }) + }) : filteredStock.map((s, idx) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: idx + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: s.item_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [s.generic_name || 'Allopathic', " • HSN: ", s.hsn_code || '3004'] + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary", + children: s.category || 'Medicine' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border fw-bold", + children: s.batch_no + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [s.shelf_no ? `Sh: ${s.shelf_no}` : '', " ", s.rack_no ? `• Rk: ${s.rack_no}` : s.shelf_no ? '' : '-'] + }) + }), /*#__PURE__*/_jsx("td", { + children: s.expiry_display || s.expiry_date + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: [/*#__PURE__*/_jsx("span", { + className: `fw-bolder fs-6 ${s.current_qty <= (s.min_reorder_level || 5) ? 'text-danger' : 'text-success'}`, + children: s.current_qty + }), /*#__PURE__*/_jsx("small", { + className: "text-muted d-block", + style: { + fontSize: '0.7rem' + }, + children: "Units" + })] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: ["₹", s.ptr] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-semibold", + children: ["₹", s.mrp] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", s.cost_valuation] + }), /*#__PURE__*/_jsx("td", { + children: s.is_expired ? /*#__PURE__*/_jsx("span", { + className: "badge-expired", + children: "EXPIRED" + }) : s.is_near_expiry ? /*#__PURE__*/_jsx("span", { + className: "badge-near-expiry", + children: "Near Expiry" + }) : /*#__PURE__*/_jsx("span", { + className: "badge-fefo", + children: "Good Stock" + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-primary py-1 px-2.5 rounded-pill shadow-xs d-inline-flex align-items-center gap-1", + title: "Check physical stock against system record & adjust", + onClick: () => openReconcileModal(s), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-sliders2" + }), " Reconcile"] + }) + })] + }, s.stock_id)) + })] + }) + }) + })] + }), invSubTab === 'physical_audit' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3 border-start border-4 border-info", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("div", { + style: { + minWidth: 180 + }, + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Filter by Shelf / Rack" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: cycleRackFilter, + onChange: e => setCycleRackFilter(e.target.value), + children: [/*#__PURE__*/_jsxs("option", { + value: "all", + children: ["All Racks & Shelves (", stock.length, " batches)"] + }), uniqueRacks.map(r => /*#__PURE__*/_jsxs("option", { + value: r, + children: ["Rack: ", r] + }, r))] + })] + }), /*#__PURE__*/_jsxs("div", { + style: { + minWidth: 220 + }, + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Search Medicine / Batch" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "Type item or batch...", + value: cycleSearch, + onChange: e => setCycleSearch(e.target.value) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsx("div", { + className: "small text-muted fw-bold text-uppercase", + children: "Discrepancies Found" + }), /*#__PURE__*/_jsxs("div", { + className: "fw-bolder fs-5 text-dark", + children: [/*#__PURE__*/_jsxs("span", { + className: cycleDiscrepancyCount > 0 ? 'text-danger' : 'text-success', + children: [cycleDiscrepancyCount, " items"] + }), cycleDiscrepancyCount > 0 && /*#__PURE__*/_jsxs("span", { + className: "small text-muted ms-1", + children: ["(₹", cycleDiscrepancyValue.toFixed(2), ")"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-primary btn-sm px-3 py-2 fw-bold shadow-sm d-flex align-items-center gap-1.5", + onClick: handleCommitCycleAudit, + disabled: isCommittingCycle || cycleDiscrepancyCount === 0, + children: isCommittingCycle ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm" + }), " Committing..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cloud-arrow-up-fill" + }), " Commit Cycle Count (", cycleDiscrepancyCount, ")"] + }) + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-0 overflow-hidden shadow-sm", + children: /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos table-hover align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Item" + }), /*#__PURE__*/_jsx("th", { + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + children: "Location" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 110 + }, + children: "System Qty" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 140 + }, + children: "Physical Count" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 110 + }, + children: "Variance" + }), /*#__PURE__*/_jsx("th", { + style: { + minWidth: 170 + }, + children: "Audit Reason" + }), /*#__PURE__*/_jsx("th", { + style: { + minWidth: 180 + }, + children: "Remarks / Notes" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: cycleFilteredStock.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "10", + className: "text-center py-5 text-muted", + children: "No items found in this shelf/rack." + }) + }) : cycleFilteredStock.map((item, idx) => { + const countData = cycleCounts[item.batch_id] || {}; + const hasInput = countData.physical_qty !== undefined && countData.physical_qty !== ''; + const pVal = hasInput ? Number(countData.physical_qty) : null; + const sVal = Number(item.current_qty); + const diff = pVal !== null ? pVal - sVal : 0; + const rate = Number(item.ptr || item.mrp || 0); + return /*#__PURE__*/_jsxs("tr", { + className: diff !== 0 && hasInput ? diff < 0 ? 'table-danger-subtle' : 'table-info-subtle' : '', + children: [/*#__PURE__*/_jsx("td", { + children: idx + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: item.item_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [item.generic_name, " • Packing: ", item.unit_pack || 'Unit'] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border fw-bold", + children: item.batch_no + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '0.7rem' + }, + children: ["Exp: ", item.expiry_display || item.expiry_date] + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [item.shelf_no ? `Sh: ${item.shelf_no}` : '', " ", item.rack_no ? `• Rk: ${item.rack_no}` : item.shelf_no ? '' : 'Normal'] + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary fs-6 px-2 py-1 fw-bolder", + children: sVal + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsx("input", { + type: "number", + min: "0", + className: `form-control form-control-sm text-center fw-bolder ${hasInput ? diff === 0 ? 'is-valid' : 'is-invalid' : ''}`, + placeholder: sVal, + value: countData.physical_qty !== undefined ? countData.physical_qty : '', + onChange: e => handleCycleCountChange(item.batch_id, e.target.value) + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: hasInput ? diff === 0 ? /*#__PURE__*/_jsx("span", { + className: "badge bg-success-subtle text-success fw-bold px-2 py-1", + children: "✓ Match (0)" + }) : diff < 0 ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger text-white fw-bold px-2 py-1", + title: `Shortage: ₹${(Math.abs(diff) * rate).toFixed(2)}`, + children: [diff, " Units"] + }) : /*#__PURE__*/_jsxs("span", { + className: "badge bg-info text-dark fw-bold px-2 py-1", + title: `Surplus: ₹${(diff * rate).toFixed(2)}`, + children: ["+", diff, " Units"] + }) : /*#__PURE__*/_jsx("span", { + className: "text-muted small", + children: "-" + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + disabled: !hasInput || diff === 0, + value: countData.audit_type || 'PHYSICAL_VARIATION', + onChange: e => handleCycleReasonChange(item.batch_id, e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "PHYSICAL_VARIATION", + children: "Shelf Miscount" + }), /*#__PURE__*/_jsx("option", { + value: "DAMAGE", + children: "Damaged Packaging" + }), /*#__PURE__*/_jsx("option", { + value: "BREAKAGE", + children: "Bottle Broken / Spilt" + }), /*#__PURE__*/_jsx("option", { + value: "EXPIRY_DUMP", + children: "Expired On Shelf" + }), /*#__PURE__*/_jsx("option", { + value: "SURPLUS_FOUND", + children: "Surplus Found" + }), /*#__PURE__*/_jsx("option", { + value: "THEFT_LOSS", + children: "Unaccounted Shortage" + })] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + disabled: !hasInput, + placeholder: "Note / Shelf position", + value: countData.remarks || '', + onChange: e => handleCycleRemarksChange(item.batch_id, e.target.value) + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: hasInput && /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-secondary py-0.5 px-1.5", + title: "Clear entered count", + onClick: () => handleCycleCountChange(item.batch_id, ''), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + }) + })] + }, item.batch_id); + }) + })] + }) + }) + })] + }), invSubTab === 'audit_logs' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2 align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-3 col-sm-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Audit Type / Reason" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: auditFilterType, + onChange: e => setAuditFilterType(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "all", + children: "All Audit Events & Movements" + }), /*#__PURE__*/_jsx("option", { + value: "PHYSICAL_VARIATION", + children: "Physical Variation (Shelf vs System)" + }), /*#__PURE__*/_jsx("option", { + value: "DAMAGE", + children: "Damaged Packaging" + }), /*#__PURE__*/_jsx("option", { + value: "BREAKAGE", + children: "Breakage / Spillage" + }), /*#__PURE__*/_jsx("option", { + value: "EXPIRY_DUMP", + children: "Expired Stock Dump" + }), /*#__PURE__*/_jsx("option", { + value: "SURPLUS_FOUND", + children: "Surplus Stock Found" + }), /*#__PURE__*/_jsx("option", { + value: "THEFT_LOSS", + children: "Unaccounted Loss / Pilferage" + }), /*#__PURE__*/_jsx("option", { + value: "PURCHASE", + children: "Purchase Inward" + }), /*#__PURE__*/_jsx("option", { + value: "SALE", + children: "Sale Dispensation" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3 col-sm-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "Search Medicine / Auditor" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "Item, batch, auditor...", + value: auditSearch, + onChange: e => setAuditSearch(e.target.value), + onKeyDown: e => { + if (e.key === 'Enter') loadAuditLogs(); + } + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary", + onClick: loadAuditLogs, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-sm-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "From Date" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: auditFromDate, + onChange: e => setAuditFromDate(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-sm-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-muted mb-1", + children: "To Date" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: auditToDate, + onChange: e => setAuditToDate(e.target.value) + })] + }), /*#__PURE__*/_jsx("div", { + className: "col-md-2 col-sm-4 d-flex align-items-end", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary w-100 d-flex align-items-center justify-content-center gap-1", + onClick: loadAuditLogs, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }), " Refresh Logs"] + }) + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-0 overflow-hidden shadow-sm", + children: /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos table-hover align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "# & Timestamp" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Item" + }), /*#__PURE__*/_jsx("th", { + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + children: "System Qty" + }), /*#__PURE__*/_jsx("th", { + children: "Physical Qty" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Variance Qty" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Valuation (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "Audit Event / Reason" + }), /*#__PURE__*/_jsx("th", { + children: "Remarks" + }), /*#__PURE__*/_jsx("th", { + children: "Conducted By" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: loadingAuditLogs ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "10", + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split fs-3 d-block mb-2 text-primary" + }), " Loading audit trail..."] + }) + }) : auditLogs.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "10", + className: "text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clipboard-check fs-3 d-block mb-1 text-secondary" + }), "No stock audit events recorded yet for this criteria."] + }) + }) : auditLogs.map(log => { + const vQty = Number(log.variation_qty || 0); + return /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark", + children: ["#", log.audit_id] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '0.72rem' + }, + children: log.created_at + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: log.item_name || `Item #${log.item_id}` + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [log.generic_name, " • ", log.unit_pack || 'Unit'] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border fw-bold", + children: log.batch_no || `Batch #${log.batch_id}` + }), log.expiry_date && /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '0.7rem' + }, + children: ["Exp: ", log.expiry_date] + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "fw-semibold text-secondary", + children: log.system_qty + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "fw-bold text-dark", + children: log.physical_qty + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: vQty === 0 ? /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary fw-semibold", + children: "0" + }) : vQty < 0 ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger text-white fw-bold px-2 py-1", + children: [vQty, " Units"] + }) : /*#__PURE__*/_jsxs("span", { + className: "badge bg-success text-white fw-bold px-2 py-1", + children: ["+", vQty, " Units"] + }) + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", Number(log.total_value || 0).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge ${log.audit_type === 'PHYSICAL_VARIATION' ? 'bg-warning-subtle text-dark border border-warning' : log.audit_type === 'DAMAGE' || log.audit_type === 'BREAKAGE' ? 'bg-danger-subtle text-danger border border-danger' : log.audit_type === 'EXPIRY_DUMP' ? 'bg-dark text-white' : log.audit_type === 'SURPLUS_FOUND' ? 'bg-info-subtle text-info border border-info' : log.audit_type === 'PURCHASE' ? 'bg-success-subtle text-success border border-success' : 'bg-secondary-subtle text-secondary'}`, + children: log.audit_type ? log.audit_type.replace(/_/g, ' ') : 'AUDIT' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-muted text-break", + children: log.remarks || '-' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person me-1" + }), log.conducted_by_name || 'Staff'] + }) + })] + }, log.audit_id); + }) + })] + }) + }) + })] + }), reconcileModalItem && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)', + zIndex: 10650 + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + style: { + maxWidth: 540 + }, + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-2xl rounded-4 overflow-hidden", + style: { + background: '#0f172a', + color: '#f8fafc', + border: '1px solid #334155' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header border-bottom border-secondary py-3 px-4", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "p-2 rounded-3 bg-primary bg-opacity-25 text-primary", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-sliders2 fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold text-white mb-0", + children: "Stock Reconciliation & Discrepancy Audit" + }), /*#__PURE__*/_jsxs("small", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: [store.store_name, " • Physical vs System Shelf Count"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setReconcileModalItem(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 mb-3 border border-secondary", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white fs-6", + children: reconcileModalItem.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400 small mb-2", + style: { + color: '#94a3b8' + }, + children: [reconcileModalItem.generic_name, " • Unit Pack: ", reconcileModalItem.unit_pack || 'Unit'] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 small", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("span", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: "Batch No:" + }), " ", /*#__PURE__*/_jsx("strong", { + className: "text-cyan-300", + style: { + color: '#67e8f9' + }, + children: reconcileModalItem.batch_no + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("span", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: "Expiry:" + }), " ", /*#__PURE__*/_jsx("strong", { + className: "text-white", + children: reconcileModalItem.expiry_display || reconcileModalItem.expiry_date + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("span", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: "PTR / Cost:" + }), " ", /*#__PURE__*/_jsxs("strong", { + className: "text-white", + children: ["₹", reconcileModalItem.ptr] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("span", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: "MRP:" + }), " ", /*#__PURE__*/_jsxs("strong", { + className: "text-white", + children: ["₹", reconcileModalItem.mrp] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 border border-secondary text-center", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-slate-400 text-uppercase fw-bold d-block", + style: { + color: '#94a3b8' + }, + children: "System Stock" + }), /*#__PURE__*/_jsx("span", { + className: "fs-3 fw-bolder text-white", + children: reconcileModalItem.current_qty + }), /*#__PURE__*/_jsx("span", { + className: "small text-slate-400 ms-1", + style: { + color: '#94a3b8' + }, + children: "Units" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 border border-primary text-center", + style: { + background: 'rgba(14, 165, 233, 0.15)' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-cyan-300 text-uppercase fw-bold d-block", + style: { + color: '#38bdf8' + }, + children: "Physical Shelf Count" + }), /*#__PURE__*/_jsx("input", { + type: "number", + min: "0", + className: "form-control form-control-lg text-center fw-bolder text-cyan-300 border-primary mt-1 bg-dark", + value: reconcilePhysicalQty, + onChange: e => setReconcilePhysicalQty(e.target.value), + autoFocus: true + })] + }) + })] + }), (() => { + const sys = Number(reconcileModalItem.current_qty || 0); + const phy = Number(reconcilePhysicalQty !== '' ? reconcilePhysicalQty : sys); + const diff = phy - sys; + const rate = Number(reconcileModalItem.ptr || reconcileModalItem.mrp || 0); + const val = Math.abs(diff) * rate; + if (diff === 0) { + return /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-success d-flex align-items-center gap-2 mb-3 small", + style: { + background: 'rgba(16, 185, 129, 0.15)', + color: '#34d399' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Counts Match Perfectly." + }), " Physical shelf count equals system record (0 discrepancy)."] + })] + }); + } else if (diff < 0) { + return /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-danger d-flex align-items-center gap-2 mb-3 small", + style: { + background: 'rgba(239, 68, 68, 0.15)', + color: '#f87171' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-octagon-fill fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("strong", { + children: ["Shortage Detected: ", Math.abs(diff), " Units Short"] + }), /*#__PURE__*/_jsxs("div", { + className: "text-white-50", + children: ["Estimated Discrepancy Value: ", /*#__PURE__*/_jsxs("strong", { + children: ["₹", val.toFixed(2)] + }), " (System ", sys, " > Shelf ", phy, ")"] + })] + })] + }); + } else { + return /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-info d-flex align-items-center gap-2 mb-3 small", + style: { + background: 'rgba(14, 165, 233, 0.15)', + color: '#38bdf8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle-fill fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("strong", { + children: ["Surplus Stock: +", diff, " Extra Units Found"] + }), /*#__PURE__*/_jsxs("div", { + className: "text-white-50", + children: ["Estimated Valuation: ", /*#__PURE__*/_jsxs("strong", { + children: ["₹", val.toFixed(2)] + }), " (Shelf ", phy, " > System ", sys, ")"] + })] + })] + }); + } + })(), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold", + style: { + color: '#cbd5e1' + }, + children: "Audit Reason / Discrepancy Cause" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm bg-dark text-white border-secondary", + value: reconcileAuditType, + onChange: e => setReconcileAuditType(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "PHYSICAL_VARIATION", + children: "Physical Count Variation (Shelf vs System Count)" + }), /*#__PURE__*/_jsx("option", { + value: "DAMAGE", + children: "Damaged Packaging / Foil Broken" + }), /*#__PURE__*/_jsx("option", { + value: "BREAKAGE", + children: "Breakage / Spillage / Bottle Leakage" + }), /*#__PURE__*/_jsx("option", { + value: "EXPIRY_DUMP", + children: "Expired Stock (Disposed from Shelf)" + }), /*#__PURE__*/_jsx("option", { + value: "SURPLUS_FOUND", + children: "Unrecorded Surplus Stock Found" + }), /*#__PURE__*/_jsx("option", { + value: "THEFT_LOSS", + children: "Unaccounted Discrepancy / Shrinkage" + }), /*#__PURE__*/_jsx("option", { + value: "AUDIT_CORRECTION", + children: "Manual Inventory Correction" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold", + style: { + color: '#cbd5e1' + }, + children: "Audit Remarks & Shelf Notes" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "e.g., Verified on shelf during physical stock take", + value: reconcileRemarks, + onChange: e => setReconcileRemarks(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between p-2.5 rounded-3 border border-secondary small", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: ["Audited By: ", /*#__PURE__*/_jsx("strong", { + className: "text-white", + children: activeOperator ? activeOperator.full_name : 'Store Staff' + }), " (", activeOperator?.user_role || 'auditor', ")"] + }), /*#__PURE__*/_jsxs("span", { + className: "text-slate-400", + style: { + color: '#94a3b8' + }, + children: ["Date: ", /*#__PURE__*/_jsx("strong", { + className: "text-white", + children: new Date().toLocaleDateString('en-IN') + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer border-top border-secondary py-2 px-4", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setReconcileModalItem(null), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-primary px-3 fw-bold d-flex align-items-center gap-1.5", + onClick: handleReconcileSubmit, + disabled: isSubmittingReconcile, + children: isSubmittingReconcile ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm" + }), " Reconciling..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-lg" + }), " Commit Stock Adjustment"] + }) + })] + })] + }) + }) + })] + }); +} + +// ========================================================================= +// 3. INWARD PURCHASES, SUPPLIERS & EXCEL / CSV IMPORT +// ========================================================================= +function PurchaseView({ + store, + notify, + activeOperator +}) { + if (!store) return null; + const [subTab, setSubTab] = useState('inward'); // inward, excel, suppliers + const [suppliers, setSuppliers] = useState([]); + const [selectedSupplierId, setSelectedSupplierId] = useState(''); + const [invoiceNo, setInvoiceNo] = useState(''); + const [invoiceDate, setInvoiceDate] = useState(new Date().toISOString().split('T')[0]); + + // Supplier Add/Edit Modal State + const [showSupplierModal, setShowSupplierModal] = useState(false); + const [supplierSearch, setSupplierSearch] = useState(''); + const [isSavingSupplier, setIsSavingSupplier] = useState(false); + const [supplierForm, setSupplierForm] = useState({ + supplier_id: 0, + supplier_name: '', + contact_person: '', + phone: '', + email: '', + gstin: '', + pan_no: '', + dl_no_20b: '', + dl_no_21b: '', + state_code: '07', + credit_days: 30, + address: '', + bank_details: '' + }); + + // Master Medicine Autocomplete & Add Modal State + const [activeSearchRow, setActiveSearchRow] = useState(null); + const [suggestions, setSuggestions] = useState([]); + const [isSearchingMeds, setIsSearchingMeds] = useState(false); + const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1); + const activeSuggestionRef = useRef(null); + const suggestionsDropdownRef = useRef(null); + const [showMasterModal, setShowMasterModal] = useState(false); + const [masterTargetRow, setMasterTargetRow] = useState(null); + const [supportData, setSupportData] = useState({ + formulations: [], + companies: [], + gst_rates: [0, 5, 18, 40, 12, 28], + schedules: [] + }); + const [isSavingMaster, setIsSavingMaster] = useState(false); + const [masterForm, setMasterForm] = useState({ + item_name: '', + generic_name: '', + formulation: 'Tablet', + units_per_pack: 10, + packing: '10', + hsn_code: '3004', + gst_rate: 5, + drug_schedule: 'Schedule H', + company_name: '', + min_reorder_level: 10 + }); + const searchTimerRef = useRef(null); + const [rows, setRows] = useState([]); + + // --- Delivery Challans & Product History States --- + const [isChallan, setIsChallan] = useState(false); + const [supplierChallans, setSupplierChallans] = useState([]); + const [isLoadingChallans, setIsLoadingChallans] = useState(false); + const [convertedChallanId, setConvertedChallanId] = useState(null); + const [productHistory, setProductHistory] = useState([]); + const [isLoadingProductHistory, setIsLoadingProductHistory] = useState(false); + const [historyTargetItemName, setHistoryTargetItemName] = useState(''); + + // --- Active Item Form State (Pharma Purchase Input - Image 2) --- + const initialItemForm = { + item_id: 0, + product_master_id: 0, + item_name: '', + generic_name: '', + category: 'Tablet', + units_per_pack: 10, + batch_no: '', + exp_month: String(new Date().getMonth() + 1).padStart(2, '0'), + exp_year: String(new Date().getFullYear() + 2).slice(-2), + mrp: '', + qty_packs: 1, + free_qty_packs: 0, + ptr: '', + amount: 0, + discount_pct: 0, + sch_disc_amount: 0, + sch_disc_pct: 0, + taxable_amount: 0, + cgst_pct: 6.0, + sgst_pct: 6.0, + net_amount: 0, + selling_price: '', + hsn_code: '3004', + storage_type: 'Normal', + shelf_no: '', + rack_no: '', + challan_item_ref_id: 0 + }; + const [itemForm, setItemForm] = useState(initialItemForm); + const [editingItemIndex, setEditingItemIndex] = useState(null); + const recomputeItemForm = updated => { + let ptr = parseFloat(updated.ptr) || 0; + const qty = parseFloat(updated.qty_packs) || 0; + const disc = parseFloat(updated.discount_pct) || 0; + const schAmt = parseFloat(updated.sch_disc_amount) || 0; + const schDisc = parseFloat(updated.sch_disc_pct) || 0; + if (schDisc > 0) { + ptr = ptr - ptr * schDisc / 100; + } + let amount = ptr * qty; + if (schAmt > 0) { + amount = Math.max(0, amount - schAmt); + } + const taxable = amount - amount * disc / 100; + const cgst = parseFloat(updated.cgst_pct) || 0; + const sgst = parseFloat(updated.sgst_pct) || 0; + const cgstAmt = taxable * (cgst / 100); + const sgstAmt = taxable * (sgst / 100); + const net = taxable + cgstAmt + sgstAmt; + let sellingPrice = updated.selling_price; + if (!sellingPrice && updated.mrp) { + sellingPrice = updated.mrp; + } + return { + ...updated, + amount: Number(amount.toFixed(2)), + taxable_amount: Number(taxable.toFixed(2)), + net_amount: Number(net.toFixed(2)), + selling_price: sellingPrice + }; + }; + const handleItemFormChange = (field, val) => { + setItemForm(prev => { + const next = { + ...prev, + [field]: val + }; + if (field === 'mrp' && (!prev.selling_price || prev.selling_price == prev.mrp)) { + next.selling_price = val; + } + return recomputeItemForm(next); + }); + }; + const resetItemForm = (shouldFocusSearch = false) => { + setItemForm(initialItemForm); + setEditingItemIndex(null); + setSelectedSuggestionIndex(-1); + setActiveSearchRow(false); + setSuggestions([]); + if (shouldFocusSearch) { + setTimeout(() => { + const searchInput = document.getElementById('pharma_product_search_input'); + if (searchInput) { + searchInput.focus(); + searchInput.select(); + } + }, 80); + } + }; + const handleFieldKeyDown = (e, nextFieldId) => { + if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { + e.preventDefault(); + handleAddOrUpdateItem(); + return; + } + if (e.key === 'Enter') { + e.preventDefault(); + if (nextFieldId === 'submit') { + handleAddOrUpdateItem(); + } else if (nextFieldId) { + const el = document.getElementById(nextFieldId); + if (el) { + el.focus(); + if (el.select) el.select(); + } + } + } + }; + const billTotals = useMemo(() => { + let totalTaxable = 0; + let totalCgst = 0; + let totalSgst = 0; + let totalNet = 0; + rows.forEach(r => { + const taxable = Number(r.taxable_amount) || 0; + const cgst = Number(r.cgst_amount) || taxable * ((Number(r.cgst_pct) || (Number(r.gst_rate) || 12) / 2) / 100); + const sgst = Number(r.sgst_amount) || taxable * ((Number(r.sgst_pct) || (Number(r.gst_rate) || 12) / 2) / 100); + const net = Number(r.net_amount) || taxable + cgst + sgst; + totalTaxable += taxable; + totalCgst += cgst; + totalSgst += sgst; + totalNet += net; + }); + return { + taxable: totalTaxable.toFixed(2), + cgst: totalCgst.toFixed(2), + sgst: totalSgst.toFixed(2), + net: totalNet.toFixed(2) + }; + }, [rows]); + const fetchSupplierChallans = async supplierId => { + if (!supplierId) { + setSupplierChallans([]); + return; + } + setIsLoadingChallans(true); + try { + const res = await fetch(API_BASE + 'supplier-challans/' + supplierId); + const data = await res.json(); + if (data.status && data.challans) { + setSupplierChallans(data.challans); + } else { + setSupplierChallans([]); + } + } catch (e) { + console.error('fetchSupplierChallans error:', e); + setSupplierChallans([]); + } finally { + setIsLoadingChallans(false); + } + }; + const fetchProductPurchaseHistory = async (itemId, itemName = '') => { + if (!itemId) { + setProductHistory([]); + setHistoryTargetItemName(''); + return; + } + setIsLoadingProductHistory(true); + setHistoryTargetItemName(itemName || 'Selected Product'); + try { + const res = await fetch(API_BASE + 'product-purchase-history/' + itemId); + const data = await res.json(); + if (data.status && data.history) { + setProductHistory(data.history); + } else { + setProductHistory([]); + } + if (data.status && data.latest_info) { + const info = data.latest_info; + setItemForm(prev => recomputeItemForm({ + ...prev, + batch_no: info.batch_no || prev.batch_no, + exp_month: info.exp_month || prev.exp_month, + exp_year: info.exp_year || prev.exp_year, + expiry_date: info.expiry_date || prev.expiry_date, + mrp: info.mrp !== undefined && info.mrp !== '' ? Number(info.mrp) : prev.mrp, + ptr: info.ptr !== undefined && info.ptr !== '' ? Number(info.ptr) : prev.ptr, + discount_pct: info.discount_pct !== undefined ? Number(info.discount_pct) : prev.discount_pct, + gst_rate: info.gst_rate !== undefined ? Number(info.gst_rate) : prev.gst_rate, + cgst_pct: info.cgst_pct !== undefined ? Number(info.cgst_pct) : prev.cgst_pct, + sgst_pct: info.sgst_pct !== undefined ? Number(info.sgst_pct) : prev.sgst_pct, + hsn_code: info.hsn_code || prev.hsn_code || '3004', + shelf_no: info.shelf_no || prev.shelf_no, + rack_no: info.rack_no || prev.rack_no, + storage_type: info.storage_type || prev.storage_type || 'Normal', + units_per_pack: info.units_per_pack ? Number(info.units_per_pack) : prev.units_per_pack || 10, + selling_price: info.selling_price ? Number(info.selling_price) : info.mrp ? Number(info.mrp) : prev.selling_price + })); + } + } catch (e) { + console.error('fetchProductPurchaseHistory error:', e); + setProductHistory([]); + } finally { + setIsLoadingProductHistory(false); + } + }; + const handleAddOrUpdateItem = () => { + if (!itemForm.item_name.trim()) { + notify('Please select or enter a medicine name.', 'error'); + return; + } + if (!itemForm.batch_no.trim()) { + notify('Please enter a Batch Number.', 'error'); + return; + } + const qtyPacks = Number(itemForm.qty_packs); + if (isNaN(qtyPacks) || qtyPacks === 0) { + notify('Quantity in packs cannot be 0. Enter positive qty for stock entry, or negative qty for return/debit.', 'error'); + return; + } + const isReturnItem = qtyPacks < 0; + const yy = String(itemForm.exp_year).length === 2 ? '20' + itemForm.exp_year : String(itemForm.exp_year); + const mm = String(itemForm.exp_month).padStart(2, '0'); + const expiryDate = `${yy}-${mm}-01`; + const rowItem = recomputeItemForm({ + ...itemForm, + expiry_date: expiryDate, + exp_month: mm, + exp_year: itemForm.exp_year, + is_return: isReturnItem, + gst_rate: (Number(itemForm.cgst_pct) || 0) + (Number(itemForm.sgst_pct) || 0) + }); + if (editingItemIndex !== null && editingItemIndex >= 0 && editingItemIndex < rows.length) { + const nextRows = [...rows]; + nextRows[editingItemIndex] = rowItem; + setRows(nextRows); + setEditingItemIndex(null); + notify(`Updated "${rowItem.item_name}" in invoice items list.`, 'success'); + } else { + setRows(prev => [...prev, rowItem]); + if (isReturnItem) { + notify(`Added Return / Debit item "${rowItem.item_name}" (${rowItem.qty_packs} packs, ₹${rowItem.net_amount}) to invoice.`, 'warning'); + } else { + notify(`Added "${rowItem.item_name}" to invoice items list.`, 'success'); + } + } + resetItemForm(true); + }; + const handleEditRow = index => { + const r = rows[index]; + if (!r) return; + setEditingItemIndex(index); + let expMonth = r.exp_month; + let expYear = r.exp_year; + if (!expMonth && r.expiry_date) { + const parts = r.expiry_date.split('-'); + if (parts.length >= 2) { + expYear = parts[0].slice(-2); + expMonth = parts[1]; + } + } + setItemForm(recomputeItemForm({ + ...initialItemForm, + ...r, + exp_month: expMonth || '12', + exp_year: expYear || '28', + cgst_pct: r.cgst_pct !== undefined ? r.cgst_pct : (r.gst_rate || 12) / 2, + sgst_pct: r.sgst_pct !== undefined ? r.sgst_pct : (r.gst_rate || 12) / 2 + })); + if (r.item_id > 0) { + fetchProductPurchaseHistory(r.item_id, r.item_name); + } + setTimeout(() => { + const qtyInput = document.getElementById('pharma_qty_input'); + if (qtyInput) { + qtyInput.focus(); + qtyInput.select(); + } + }, 120); + }; + const includeChallanItem = (challan, cItem) => { + let expMonth = '12'; + let expYear = '28'; + if (cItem.expiry_date) { + const parts = cItem.expiry_date.split('-'); + if (parts.length >= 2) { + expYear = parts[0].slice(-2); + expMonth = parts[1]; + } + } + const cgst = (cItem.gst_rate || 12) / 2; + const sgst = (cItem.gst_rate || 12) / 2; + const rowItem = recomputeItemForm({ + item_id: cItem.item_id || 0, + product_master_id: 0, + item_name: cItem.item_name, + generic_name: cItem.generic_name || '', + category: cItem.category || 'Tablet', + units_per_pack: Number(cItem.units_per_pack) || 10, + batch_no: cItem.batch_no || 'CHL-BATCH', + exp_month: expMonth, + exp_year: expYear, + expiry_date: cItem.expiry_date || `${'20' + expYear}-${expMonth}-01`, + mrp: Number(cItem.mrp) || 0, + qty_packs: Number(cItem.qty_packs) || 1, + free_qty_packs: Number(cItem.free_qty_packs) || 0, + ptr: Number(cItem.ptr) || 0, + discount_pct: Number(cItem.discount_pct) || 0, + sch_disc_amount: Number(cItem.sch_disc_amount) || 0, + sch_disc_pct: Number(cItem.sch_disc_pct) || 0, + cgst_pct: cgst, + sgst_pct: sgst, + gst_rate: cItem.gst_rate || 12, + selling_price: Number(cItem.selling_price) || Number(cItem.mrp) || 0, + hsn_code: cItem.hsn_code || '3004', + storage_type: cItem.storage_type || 'Normal', + shelf_no: cItem.shelf_no || '', + rack_no: cItem.rack_no || '', + challan_item_ref_id: cItem.challan_ref_id || challan.id + }); + setConvertedChallanId(challan.id); + setRows(prev => [...prev, rowItem]); + notify(`Challan item "${cItem.item_name}" included into invoice!`, 'success'); + }; + const includeAllChallanItems = challan => { + if (!challan.items || challan.items.length === 0) return; + challan.items.forEach(cItem => includeChallanItem(challan, cItem)); + notify(`All ${challan.items.length} items from Challan #${challan.challan_no} included into invoice!`, 'success'); + }; + + // --- Supplier Ledger & Payments States --- + const [ledgerSummary, setLedgerSummary] = useState([]); + const [ledgerOverall, setLedgerOverall] = useState({ + total_purchases: 0, + total_paid: 0, + outstanding_balance: 0, + total_pending_bills: 0, + total_suppliers: 0 + }); + const [activeLedgerSupplierId, setActiveLedgerSupplierId] = useState(''); + const [activeLedgerDetail, setActiveLedgerDetail] = useState(null); + const [isLoadingLedger, setIsLoadingLedger] = useState(false); + const [showPaymentModal, setShowPaymentModal] = useState(false); + const [isRecordingPayment, setIsRecordingPayment] = useState(false); + const [paymentForm, setPaymentForm] = useState({ + supplier_id: '', + purchase_id: '', + amount: '', + payment_mode: 'Bank', + reference_no: '', + bank_name: '', + payment_date: new Date().toISOString().split('T')[0], + remarks: '' + }); + + // --- Short Items / Deficiency Reorder States --- + const [shortItems, setShortItems] = useState([]); + const [selectedShortItemIds, setSelectedShortItemIds] = useState([]); + const [shortFilter, setShortFilter] = useState('all'); // all, out_of_stock, low_stock + const [shortSearch, setShortSearch] = useState(''); + const [isLoadingShortItems, setIsLoadingShortItems] = useState(false); + const [showQuickReorderModal, setShowQuickReorderModal] = useState(false); + const [quickReorderForm, setQuickReorderForm] = useState({ + item_id: '', + item_name: '', + min_reorder_level: 10 + }); + const [isSavingShortItem, setIsSavingShortItem] = useState(false); + + // --- Purchase Orders States --- + const [purchaseOrders, setPurchaseOrders] = useState([]); + const [poStatusFilter, setPoStatusFilter] = useState('all'); + const [isLoadingPOs, setIsLoadingPOs] = useState(false); + const [showPoCreateModal, setShowPoCreateModal] = useState(false); + const [poCreateForm, setPoCreateForm] = useState({ + supplier_id: '', + expected_delivery_date: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], + remarks: '', + items: [] + }); + const [isSavingPO, setIsSavingPO] = useState(false); + const [showPoViewModal, setShowPoViewModal] = useState(false); + const [activeViewPo, setActiveViewPo] = useState(null); + const [loadedPoId, setLoadedPoId] = useState(null); + const [loadedPoNumber, setLoadedPoNumber] = useState(''); + + // --- Purchase Invoice History & Edit States --- + const [editingPurchaseId, setEditingPurchaseId] = useState(null); + const [recentPurchases, setRecentPurchases] = useState([]); + const [isLoadingPurchases, setIsLoadingPurchases] = useState(false); + const [showPurchaseHistoryModal, setShowPurchaseHistoryModal] = useState(false); + const [purchaseHistorySearch, setPurchaseHistorySearch] = useState(''); + + // --- Data Fetching & Action Handlers --- + const fetchLedgerSummary = async () => { + setIsLoadingLedger(true); + try { + const res = await fetch(API_BASE + 'suppliers/ledger-summary'); + const data = await res.json(); + if (data.status) { + setLedgerSummary(data.suppliers || []); + if (data.summary) setLedgerOverall(data.summary); + } + } catch (e) { + console.error('fetchLedgerSummary error:', e); + } finally { + setIsLoadingLedger(false); + } + }; + const fetchRecentPurchases = async () => { + setIsLoadingPurchases(true); + try { + const res = await fetch(API_BASE + 'purchases?store_id=' + store.store_id); + const data = await res.json(); + if (data.status && data.purchases) { + setRecentPurchases(data.purchases); + } + } catch (e) { + console.error('fetchRecentPurchases error:', e); + } finally { + setIsLoadingPurchases(false); + } + }; + const loadPurchaseForEdit = async purchaseId => { + if (!purchaseId) return; + try { + const res = await fetch(API_BASE + 'purchase/' + purchaseId); + const data = await res.json(); + if (data.status && data.purchase) { + setEditingPurchaseId(Number(data.purchase.purchase_id)); + setSelectedSupplierId(String(data.purchase.supplier_id)); + setIsChallan(Number(data.purchase.is_challan || 0) === 1); + setInvoiceNo(data.purchase.supplier_invoice_no || ''); + setInvoiceDate(data.purchase.invoice_date || new Date().toISOString().split('T')[0]); + setLoadedPoId(null); + setLoadedPoNumber(''); + if (data.items && data.items.length > 0) { + setRows(data.items.map(it => { + let expMonth = '12'; + let expYear = '28'; + if (it.expiry_date) { + const parts = it.expiry_date.split('-'); + if (parts.length >= 2) { + expYear = parts[0].slice(-2); + expMonth = parts[1]; + } + } + const gst = Number(it.gst_rate) || 12; + return recomputeItemForm({ + item_id: Number(it.item_id || 0), + product_master_id: 0, + item_name: it.item_name || '', + generic_name: it.generic_name || '', + category: it.category || 'Tablet', + units_per_pack: Number(it.units_per_pack || 10), + batch_no: it.batch_no || '', + exp_month: expMonth, + exp_year: expYear, + expiry_date: it.expiry_date || '', + mrp: Number(it.mrp || 0), + qty_packs: Number(it.qty_packs || 1), + free_qty_packs: Number(it.free_qty_packs || 0), + ptr: Number(it.ptr || 0), + discount_pct: Number(it.discount_pct || 0), + sch_disc_amount: Number(it.sch_disc_amount || 0), + sch_disc_pct: Number(it.sch_disc_pct || 0), + cgst_pct: gst / 2, + sgst_pct: gst / 2, + gst_rate: gst, + selling_price: Number(it.selling_price || it.mrp || 0), + hsn_code: it.hsn_code || '3004', + storage_type: it.storage_type || 'Normal', + shelf_no: it.shelf_no || '', + rack_no: it.rack_no || '', + challan_item_ref_id: Number(it.challan_item_ref_id || 0) + }); + })); + } + setSubTab('inward'); + setShowPurchaseHistoryModal(false); + fetchSupplierChallans(data.purchase.supplier_id); + notify('Purchase Invoice #' + data.purchase.supplier_invoice_no + ' loaded for editing.', 'info'); + } else { + notify(data.message || 'Could not load purchase details.', 'error'); + } + } catch (e) { + notify('Error loading purchase invoice: ' + e.message, 'error'); + } + }; + const cancelEditPurchase = () => { + setEditingPurchaseId(null); + setIsChallan(false); + setInvoiceNo(''); + setLoadedPoId(null); + setLoadedPoNumber(''); + setConvertedChallanId(null); + setRows([]); + resetItemForm(); + notify('Exited purchase edit mode. Ready for new inward entry.', 'info'); + }; + const fetchSupplierLedger = async supplierId => { + if (!supplierId) { + setActiveLedgerDetail(null); + return; + } + setIsLoadingLedger(true); + try { + const res = await fetch(API_BASE + 'suppliers/ledger/' + supplierId); + const data = await res.json(); + if (data.status) { + setActiveLedgerDetail(data); + } else { + notify(data.message || 'Failed to fetch supplier ledger.', 'error'); + } + } catch (e) { + notify('Error fetching ledger: ' + e.message, 'error'); + } finally { + setIsLoadingLedger(false); + } + }; + const openPaymentModal = (supplierId, purchaseId = 0, defaultAmount = 0) => { + const sId = supplierId ? String(supplierId) : activeLedgerSupplierId || ''; + setPaymentForm({ + supplier_id: sId, + purchase_id: purchaseId ? String(purchaseId) : '', + amount: defaultAmount > 0 ? defaultAmount : '', + payment_mode: 'Bank', + reference_no: '', + bank_name: '', + payment_date: new Date().toISOString().split('T')[0], + remarks: purchaseId ? 'Payment for invoice #' + purchaseId : 'On-account settlement' + }); + setShowPaymentModal(true); + }; + const handleRecordPayment = async e => { + if (e) e.preventDefault(); + const supId = Number(paymentForm.supplier_id); + const amt = parseFloat(paymentForm.amount); + if (!supId || isNaN(amt) || amt <= 0) { + notify('Please specify a supplier and valid payment amount.', 'error'); + return; + } + setIsRecordingPayment(true); + try { + const res = await fetch(API_BASE + 'suppliers/record-payment', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + supplier_id: supId, + purchase_id: Number(paymentForm.purchase_id) || 0, + amount: amt, + payment_mode: paymentForm.payment_mode, + reference_no: paymentForm.reference_no, + bank_name: paymentForm.bank_name, + payment_date: paymentForm.payment_date, + remarks: paymentForm.remarks + }) + }); + const data = await res.json(); + if (data.status) { + notify('Payment recorded! Voucher #' + data.voucher_no, 'success'); + setShowPaymentModal(false); + fetchLedgerSummary(); + if (activeLedgerSupplierId && String(activeLedgerSupplierId) === String(supId)) { + fetchSupplierLedger(supId); + } + } else { + notify(data.message || 'Failed to record payment.', 'error'); + } + } catch (err) { + notify('Payment error: ' + err.message, 'error'); + } finally { + setIsRecordingPayment(false); + } + }; + const fetchShortItems = async () => { + setIsLoadingShortItems(true); + try { + const res = await fetch(API_BASE + 'stock/short-items?store_id=' + store.store_id); + const data = await res.json(); + if (data.status) { + setShortItems(data.short_items || []); + } + } catch (e) { + console.error('fetchShortItems error:', e); + } finally { + setIsLoadingShortItems(false); + } + }; + const handleSaveShortItemFlag = async e => { + if (e) e.preventDefault(); + if (!quickReorderForm.item_id) { + notify('Please select an item to track in Short Book.', 'error'); + return; + } + setIsSavingShortItem(true); + try { + const res = await fetch(API_BASE + 'stock/flag-short-item', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + item_id: Number(quickReorderForm.item_id), + min_reorder_level: Number(quickReorderForm.min_reorder_level) || 10 + }) + }); + const data = await res.json(); + if (data.status) { + notify(data.message || 'Item updated in Short Book!', 'success'); + setShowQuickReorderModal(false); + fetchShortItems(); + } else { + notify(data.message || 'Failed to update reorder level.', 'error'); + } + } catch (err) { + notify('Error: ' + err.message, 'error'); + } finally { + setIsSavingShortItem(false); + } + }; + const fetchPurchaseOrders = async () => { + setIsLoadingPOs(true); + try { + const res = await fetch(API_BASE + 'purchase-orders?store_id=' + store.store_id + '&status=' + poStatusFilter); + const data = await res.json(); + if (data.status) { + setPurchaseOrders(data.purchase_orders || []); + } + } catch (e) { + console.error('fetchPurchaseOrders error:', e); + } finally { + setIsLoadingPOs(false); + } + }; + const openCreatePoFromShortItems = () => { + const selected = shortItems.filter(it => selectedShortItemIds.includes(it.item_id)); + if (selected.length === 0) { + notify('Please select at least one item from the short list.', 'warning'); + return; + } + const defaultSupplier = selected.find(s => s.last_supplier_id > 0)?.last_supplier_id || suppliers[0]?.supplier_id || ''; + setPoCreateForm({ + supplier_id: defaultSupplier ? String(defaultSupplier) : '', + expected_delivery_date: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], + remarks: 'Replenishment purchase order from hospital deficiency book', + items: selected.map(it => ({ + item_id: it.item_id, + item_name: it.item_name, + generic_name: it.generic_name || '', + category: it.category || 'Tablet', + order_packs: it.suggested_packs || 1, + units_per_pack: it.units_per_pack || 10, + estimated_ptr: it.last_ptr || 0, + gst_rate: it.gst_rate || 12 + })) + }); + setShowPoCreateModal(true); + }; + const handleSavePurchaseOrder = async e => { + if (e) e.preventDefault(); + const supId = Number(poCreateForm.supplier_id); + if (!supId || poCreateForm.items.length === 0) { + notify('Supplier and at least one line item are required for PO.', 'error'); + return; + } + setIsSavingPO(true); + try { + const res = await fetch(API_BASE + 'purchase-orders/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + supplier_id: supId, + expected_delivery_date: poCreateForm.expected_delivery_date, + remarks: poCreateForm.remarks, + items: poCreateForm.items + }) + }); + const data = await res.json(); + if (data.status) { + notify('Purchase Order ' + data.po_number + ' created successfully!', 'success'); + setShowPoCreateModal(false); + setSelectedShortItemIds([]); + fetchPurchaseOrders(); + setSubTab('purchase_orders'); + } else { + notify(data.message || 'Failed to create PO.', 'error'); + } + } catch (err) { + notify('PO error: ' + err.message, 'error'); + } finally { + setIsSavingPO(false); + } + }; + const handleViewPo = async poId => { + try { + const res = await fetch(API_BASE + 'purchase-orders/' + poId); + const data = await res.json(); + if (data.status) { + setActiveViewPo(data); + setShowPoViewModal(true); + } else { + notify(data.message || 'PO not found', 'error'); + } + } catch (err) { + notify('Error loading PO: ' + err.message, 'error'); + } + }; + const handleCancelPo = async poId => { + if (!confirm('Are you sure you want to cancel this Purchase Order?')) return; + try { + const res = await fetch(API_BASE + 'purchase-orders/cancel', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + po_id: poId + }) + }); + const data = await res.json(); + if (data.status) { + notify(data.message || 'PO cancelled', 'success'); + fetchPurchaseOrders(); + } else { + notify(data.message || 'Failed to cancel PO', 'error'); + } + } catch (err) { + notify('Error: ' + err.message, 'error'); + } + }; + const loadPoIntoInwardBill = async poId => { + try { + const res = await fetch(API_BASE + 'purchase-orders/' + poId); + const data = await res.json(); + if (data.status && data.purchase_order) { + const po = data.purchase_order; + const poItems = data.items || []; + setSelectedSupplierId(String(po.supplier_id)); + setLoadedPoId(po.po_id); + setLoadedPoNumber(po.po_number); + setInvoiceNo('INV-' + po.po_number); + if (poItems.length > 0) { + setRows(poItems.map(it => recomputeItemForm({ + ...initialItemForm, + item_id: it.item_id || 0, + item_name: it.item_name, + generic_name: it.generic_name || '', + category: it.category || 'Tablet', + batch_no: '', + expiry_date: '', + qty_packs: it.order_packs || 1, + free_qty_packs: 0, + units_per_pack: it.units_per_pack || 10, + mrp: it.estimated_ptr ? Math.round(Number(it.estimated_ptr) * 1.35) : 0, + ptr: Number(it.estimated_ptr) || 0, + discount_pct: 0, + gst_rate: Number(it.gst_rate) || 12, + cgst_pct: (Number(it.gst_rate) || 12) / 2, + sgst_pct: (Number(it.gst_rate) || 12) / 2, + hsn_code: '3004' + }))); + } + setSubTab('inward'); + setShowPoViewModal(false); + notify('Loaded ' + poItems.length + ' items from ' + po.po_number + '. Verify batch & expiry to record inward bill.', 'info'); + } else { + notify('Could not load PO details.', 'error'); + } + } catch (err) { + notify('Error loading PO: ' + err.message, 'error'); + } + }; + useEffect(() => { + fetchSuppliers(); + fetchMasterSupportData(); + fetchRecentPurchases(); + }, []); + + // Auto-scroll active suggestion into view when navigating with Arrow keys + useEffect(() => { + if (activeSuggestionRef.current) { + activeSuggestionRef.current.scrollIntoView({ + block: 'nearest' + }); + } + }, [selectedSuggestionIndex]); + + // Close suggestions dropdown when clicking outside + useEffect(() => { + const handleOutsideClick = e => { + const searchInput = document.getElementById('pharma_product_search_input'); + if (searchInput && searchInput.contains(e.target)) return; + if (suggestionsDropdownRef.current && suggestionsDropdownRef.current.contains(e.target)) return; + setActiveSearchRow(false); + setSelectedSuggestionIndex(-1); + }; + document.addEventListener('mousedown', handleOutsideClick); + return () => document.removeEventListener('mousedown', handleOutsideClick); + }, []); + + // Global F2 hotkey to jump to Product Search anytime + useEffect(() => { + const handleGlobalKey = e => { + if (e.key === 'F2') { + e.preventDefault(); + const searchInput = document.getElementById('pharma_product_search_input'); + if (searchInput) { + searchInput.focus(); + searchInput.select(); + } + } + }; + window.addEventListener('keydown', handleGlobalKey); + return () => window.removeEventListener('keydown', handleGlobalKey); + }, []); + const fetchMasterSupportData = async () => { + try { + const res = await fetch(API_BASE + 'items/master-support-data'); + const data = await res.json(); + if (data.status) { + setSupportData(data); + } + } catch (e) { + console.error('Error fetching master support data:', e); + } + }; + const fetchSuppliers = async () => { + try { + const res = await fetch(API_BASE + 'suppliers'); + const data = await res.json(); + if (data.status) setSuppliers(data.suppliers || []); + } catch (e) { + console.error(e); + } + }; + const openAddSupplier = () => { + setSupplierForm({ + supplier_id: 0, + supplier_name: '', + contact_person: '', + phone: '', + email: '', + gstin: '', + pan_no: '', + dl_no_20b: '', + dl_no_21b: '', + state_code: '07', + credit_days: 30, + address: '', + bank_details: '' + }); + setShowSupplierModal(true); + }; + const openEditSupplier = s => { + setSupplierForm({ + supplier_id: s.supplier_id, + supplier_name: s.supplier_name || '', + contact_person: s.contact_person || '', + phone: s.phone || '', + email: s.email || '', + gstin: s.gstin || '', + pan_no: s.pan_no || '', + dl_no_20b: s.dl_no_20b || '', + dl_no_21b: s.dl_no_21b || '', + state_code: s.state_code || '07', + credit_days: s.credit_days || 30, + address: s.address || '', + bank_details: s.bank_details || '' + }); + setShowSupplierModal(true); + }; + const handleSaveSupplier = async e => { + if (e) e.preventDefault(); + if (!supplierForm.supplier_name.trim()) { + notify('Supplier / Distributor name is required.', 'error'); + return; + } + setIsSavingSupplier(true); + try { + const res = await fetch(API_BASE + 'suppliers/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(supplierForm) + }); + const data = await res.json(); + if (data.status) { + notify(supplierForm.supplier_id ? 'Supplier updated successfully!' : 'New supplier added successfully!', 'success'); + setShowSupplierModal(false); + await fetchSuppliers(); + if (data.supplier_id) { + setSelectedSupplierId(String(data.supplier_id)); + } + } else { + notify(data.message || 'Failed to save supplier.', 'error'); + } + } catch (err) { + notify('Network error saving supplier: ' + err.message, 'error'); + } finally { + setIsSavingSupplier(false); + } + }; + const handleDeleteSupplier = async (supplierId, supplierName) => { + if (!confirm(`Are you sure you want to remove / deactivate supplier "${supplierName}"?`)) return; + try { + const res = await fetch(API_BASE + 'suppliers/delete', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + supplier_id: supplierId + }) + }); + const data = await res.json(); + if (data.status) { + notify(data.message || 'Supplier removed successfully.', 'success'); + await fetchSuppliers(); + } else { + notify(data.message || 'Failed to remove supplier.', 'error'); + } + } catch (err) { + notify('Error: ' + err.message, 'error'); + } + }; + const filteredSuppliers = suppliers.filter(s => { + if (!supplierSearch.trim()) return true; + const q = supplierSearch.toLowerCase(); + return s.supplier_name && s.supplier_name.toLowerCase().includes(q) || s.gstin && s.gstin.toLowerCase().includes(q) || s.dl_no_20b && s.dl_no_20b.toLowerCase().includes(q) || s.dl_no_21b && s.dl_no_21b.toLowerCase().includes(q) || s.phone && s.phone.toLowerCase().includes(q) || s.contact_person && s.contact_person.toLowerCase().includes(q); + }); + const addRow = () => { + setRows([...rows, { + item_id: 0, + item_name: '', + generic_name: '', + category: 'Tablet', + batch_no: '', + expiry_date: '', + qty_packs: 1, + free_qty_packs: 0, + units_per_pack: 10, + mrp: 0, + ptr: 0, + discount_pct: 0, + gst_rate: 12, + hsn_code: '3004' + }]); + }; + const updateRow = (idx, field, val) => { + const updated = [...rows]; + updated[idx][field] = val; + setRows(updated); + }; + const removeRow = idx => { + setRows(prev => prev.filter((_, i) => i !== idx)); + if (editingItemIndex === idx) { + resetItemForm(); + } + }; + + // Autocomplete searching for Medicine Name in Product Search + const handleProductSearchChange = value => { + setItemForm(prev => ({ + ...prev, + item_name: value, + item_id: 0, + product_master_id: 0 + })); + setActiveSearchRow(true); + if (searchTimerRef.current) clearTimeout(searchTimerRef.current); + if (!value.trim() || value.trim().length < 1) { + setSuggestions([]); + setSelectedSuggestionIndex(-1); + return; + } + searchTimerRef.current = setTimeout(async () => { + setIsSearchingMeds(true); + try { + const res = await fetch(API_BASE + 'items/search-master?q=' + encodeURIComponent(value.trim())); + const data = await res.json(); + if (data.status) { + const list = data.items || []; + setSuggestions(list); + setSelectedSuggestionIndex(list.length > 0 ? 0 : -1); + } + } catch (err) { + console.error('Master search error:', err); + } finally { + setIsSearchingMeds(false); + } + }, 200); + }; + const handleProductSearchKeyDown = e => { + if (!activeSearchRow || suggestions.length === 0) { + if (e.key === 'ArrowDown' && itemForm.item_name.trim().length >= 1) { + e.preventDefault(); + handleProductSearchChange(itemForm.item_name); + } + return; + } + if (e.key === 'ArrowDown') { + e.preventDefault(); + setSelectedSuggestionIndex(prev => { + if (suggestions.length === 0) return -1; + return (prev + 1) % suggestions.length; + }); + return; + } + if (e.key === 'ArrowUp') { + e.preventDefault(); + setSelectedSuggestionIndex(prev => { + if (suggestions.length === 0) return -1; + return (prev - 1 + suggestions.length) % suggestions.length; + }); + return; + } + if (e.key === 'Enter') { + e.preventDefault(); + const targetIdx = selectedSuggestionIndex >= 0 && selectedSuggestionIndex < suggestions.length ? selectedSuggestionIndex : 0; + const chosen = suggestions[targetIdx]; + if (chosen) { + handleSelectMedicine(chosen); + } + return; + } + if (e.key === 'Escape') { + e.preventDefault(); + setActiveSearchRow(false); + setSelectedSuggestionIndex(-1); + return; + } + }; + const handleSelectMedicine = item => { + const gstRate = Number(item.gst_rate) || 12; + const uPack = Number(item.units_per_pack) || 10; + const cgst = Number((gstRate / 2).toFixed(2)); + const sgst = Number((gstRate / 2).toFixed(2)); + setItemForm(prev => recomputeItemForm({ + ...prev, + item_id: item.item_id || 0, + product_master_id: item.product_master_id || item.item_id || 0, + item_name: item.item_name, + generic_name: item.generic_name || '', + category: item.category || 'Tablet', + units_per_pack: uPack, + hsn_code: item.hsn_code || '3004', + cgst_pct: cgst, + sgst_pct: sgst, + gst_rate: gstRate, + mrp: item.mrp || prev.mrp, + ptr: item.ptr || prev.ptr + })); + setActiveSearchRow(false); + setSuggestions([]); + setSelectedSuggestionIndex(-1); + if (item.item_id) { + fetchProductPurchaseHistory(item.item_id, item.item_name); + } + setTimeout(() => { + const batchInput = document.getElementById('pharma_batch_no_input'); + if (batchInput) { + batchInput.focus(); + batchInput.select(); + } + }, 120); + }; + const openAddMasterModal = (initialName = '') => { + const prefillName = initialName || itemForm.item_name || ''; + setMasterForm({ + item_name: prefillName, + generic_name: '', + formulation: 'Tablet', + units_per_pack: 10, + packing: '10', + hsn_code: '3004', + gst_rate: 12, + drug_schedule: 'Schedule H', + company_name: '', + min_reorder_level: 10 + }); + setActiveSearchRow(false); + setSuggestions([]); + setShowMasterModal(true); + }; + const handleSaveMasterMedicine = async e => { + if (e) e.preventDefault(); + if (!masterForm.item_name.trim()) { + notify('Medicine name is required.', 'error'); + return; + } + setIsSavingMaster(true); + try { + const res = await fetch(API_BASE + 'items/save-master', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(masterForm) + }); + const data = await res.json(); + if (data.status && data.item) { + notify(`"${data.item.item_name}" saved to Pharmacy Master & selected!`, 'success'); + setShowMasterModal(false); + handleSelectMedicine(data.item); + } else { + notify(data.message || 'Failed to save medicine to master.', 'error'); + } + } catch (err) { + notify('Error saving to master: ' + err.message, 'error'); + } finally { + setIsSavingMaster(false); + } + }; + const savePurchaseBill = async () => { + if (!selectedSupplierId || !invoiceNo.trim()) { + notify('Please select supplier and enter invoice / challan number.', 'error'); + return; + } + if (rows.length === 0) { + notify('Please add at least one medicine item to this inward bill using the form.', 'error'); + return; + } + try { + const itemsPayload = rows.map(r => ({ + item_id: Number(r.item_id || 0), + item_name: r.item_name, + generic_name: r.generic_name || '', + category: r.category || 'Tablet', + batch_no: r.batch_no, + expiry_date: r.expiry_date, + qty_packs: Number(r.qty_packs), + free_qty_packs: Number(r.free_qty_packs || 0), + units_per_pack: Number(r.units_per_pack || 10), + mrp: Number(r.mrp), + ptr: Number(r.ptr), + discount_pct: Number(r.discount_pct || 0), + sch_disc_amount: Number(r.sch_disc_amount || 0), + sch_disc_pct: Number(r.sch_disc_pct || 0), + gst_rate: Number(r.gst_rate || 12), + hsn_code: r.hsn_code || '3004', + selling_price: Number(r.selling_price || r.mrp || 0), + storage_type: r.storage_type || 'Normal', + shelf_no: r.shelf_no || '', + rack_no: r.rack_no || '', + challan_item_ref_id: Number(r.challan_item_ref_id || 0) + })); + const endpoint = editingPurchaseId ? API_BASE + 'purchase/update' : API_BASE + 'purchase/save'; + const payload = { + store_id: store.store_id, + supplier_id: Number(selectedSupplierId), + supplier_invoice_no: invoiceNo.trim(), + is_challan: isChallan ? 1 : 0, + challan_no: isChallan ? invoiceNo.trim() : null, + received_by_name: activeOperator?.full_name || 'Store Staff', + operator_name: activeOperator?.full_name || 'Store Staff', + user_id: activeOperator?.user_id || 1, + converted_from_challan_id: convertedChallanId, + invoice_date: invoiceDate, + items: itemsPayload + }; + if (editingPurchaseId) { + payload.purchase_id = editingPurchaseId; + } else if (loadedPoId) { + payload.po_id = loadedPoId; + } + const res = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const data = await res.json(); + if (data.status) { + if (editingPurchaseId) { + notify('Purchase invoice #' + invoiceNo + ' updated successfully! Stock & supplier ledger adjusted.', 'success'); + } else if (isChallan) { + notify('Delivery Challan #' + invoiceNo + ' recorded! Stock replenished.', 'success'); + } else { + notify('Purchase inward recorded! Stock & Supplier Ledger updated.' + (loadedPoNumber ? ' (PO ' + loadedPoNumber + ' marked as received)' : ''), 'success'); + } + setEditingPurchaseId(null); + setIsChallan(false); + setInvoiceNo(''); + setLoadedPoId(null); + setLoadedPoNumber(''); + setConvertedChallanId(null); + setRows([]); + resetItemForm(); + fetchRecentPurchases(); + if (selectedSupplierId) { + fetchSupplierChallans(selectedSupplierId); + } + if (activeLedgerSupplierId) fetchSupplierLedger(activeLedgerSupplierId); + fetchLedgerSummary(); + } else { + notify(data.message || 'Failed to save purchase invoice.', 'error'); + } + } catch (e) { + notify('Purchase invoice error: ' + e.message, 'error'); + } + }; + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-2 mb-3 align-items-center", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${subTab === 'inward' ? 'btn-primary shadow-sm' : 'btn-outline-secondary'}`, + onClick: () => setSubTab('inward'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-down me-1" + }), " Inward Purchase Bill"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${subTab === 'ledger' ? 'btn-primary shadow-sm' : 'btn-outline-secondary'}`, + onClick: () => { + setSubTab('ledger'); + fetchLedgerSummary(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-bookmark me-1" + }), " Supplier Ledger & Payments"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${subTab === 'short_items' ? 'btn-warning text-dark fw-bold shadow-sm' : 'btn-outline-secondary'}`, + onClick: () => { + setSubTab('short_items'); + fetchShortItems(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle me-1" + }), " Short Items & PO Generator", shortItems.length > 0 && /*#__PURE__*/_jsx("span", { + className: "badge bg-danger ms-1", + children: shortItems.length + })] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${subTab === 'purchase_orders' ? 'btn-primary shadow-sm' : 'btn-outline-secondary'}`, + onClick: () => { + setSubTab('purchase_orders'); + fetchPurchaseOrders(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-text me-1" + }), " Purchase Orders"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${subTab === 'suppliers' ? 'btn-primary shadow-sm' : 'btn-outline-secondary'}`, + onClick: () => setSubTab('suppliers'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-truck me-1" + }), " Supplier Directory (", suppliers.length, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${subTab === 'excel' ? 'btn-success shadow-sm' : 'btn-outline-secondary'}`, + onClick: () => setSubTab('excel'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-spreadsheet me-1" + }), " Excel / CSV Import"] + })] + }), subTab === 'inward' && /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center mb-3 gap-2", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: `bi ${isChallan ? 'bi-truck text-warning' : 'bi-receipt text-primary'} me-1.5` + }), editingPurchaseId ? `Edit Purchase Invoice #${invoiceNo}` : isChallan ? 'Distributor Delivery Challan (Stock Entry)' : 'Distributor Purchase Inward (Tax Invoice)'] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: editingPurchaseId ? `Modifying existing Bill #${invoiceNo} (Ref #${editingPurchaseId}) - adjustments reflect in stock & ledger` : isChallan ? 'Record inward stock under vendor delivery challan (can be converted to tax invoice later)' : 'Enter vendor tax invoice to replenish store inventory and post supplier ledger payable' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => { + fetchRecentPurchases(); + setShowPurchaseHistoryModal(true); + }, + title: "View recent inward bills and select one to edit", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1" + }), " Inward Bills History / Edit (", recentPurchases.length, ")"] + }), loadedPoNumber ? /*#__PURE__*/_jsxs("div", { + className: "badge bg-info-subtle text-info border border-info px-2 py-1.5 d-flex align-items-center gap-1.5", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-link-45deg fs-6" + }), /*#__PURE__*/_jsxs("span", { + children: ["Linked PO: ", /*#__PURE__*/_jsx("strong", { + children: loadedPoNumber + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-dark ms-1", + style: { + fontSize: '9px' + }, + onClick: () => { + setLoadedPoId(null); + setLoadedPoNumber(''); + }, + title: "Unlink PO" + })] + }) : /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary", + onClick: () => { + fetchPurchaseOrders(); + setSubTab('purchase_orders'); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-down-right me-1" + }), " Load from Purchase Order"] + })] + })] + }), editingPurchaseId && /*#__PURE__*/_jsxs("div", { + className: "alert alert-warning border border-warning-subtle shadow-sm py-2 px-3 mb-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-warning text-dark fs-6 px-2.5 py-1.5", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square me-1" + }), "EDIT MODE"] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("strong", { + className: "text-dark d-block", + children: ["Editing Purchase Invoice #", invoiceNo, " (Purchase ID: #", editingPurchaseId, ")"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Updating this invoice will recalculate batch stock in this store and adjust supplier ledger balances." + })] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-outline-dark btn-sm fw-semibold", + onClick: cancelEditPurchase, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " Cancel Edit & New Inward"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 mb-3", + style: { + background: '#f8fafc', + borderRadius: '10px' + }, + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2 align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-0", + children: ["Supplier / Distributor ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-link btn-sm p-0 text-decoration-none fw-semibold", + style: { + fontSize: '11px' + }, + onClick: openAddSupplier, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle me-1" + }), "+ Add New"] + })] + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: selectedSupplierId, + onChange: e => { + const sId = e.target.value; + setSelectedSupplierId(sId); + fetchSupplierChallans(sId); + }, + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "-- Select Supplier --" + }), suppliers.map(s => /*#__PURE__*/_jsxs("option", { + value: s.supplier_id, + children: [s.supplier_name, " (GST: ", s.gstin || 'N/A', ")"] + }, s.supplier_id))] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Entry Type" + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm w-100", + role: "group", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${!isChallan ? 'btn-primary fw-bold' : 'btn-outline-secondary'}`, + onClick: () => setIsChallan(false), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt me-1" + }), " Tax Invoice"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn ${isChallan ? 'btn-warning text-dark fw-bold' : 'btn-outline-secondary'}`, + onClick: () => setIsChallan(true), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-truck me-1" + }), " Challan"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: [isChallan ? 'Challan Number' : 'Bill / Invoice No.', " ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: isChallan ? "e.g. CHL-2026-001" : "e.g. APX-9941", + value: invoiceNo, + onChange: e => setInvoiceNo(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: isChallan ? 'Challan Date' : 'Invoice Date' + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: invoiceDate, + onChange: e => setInvoiceDate(e.target.value) + })] + }), isChallan && /*#__PURE__*/_jsx("div", { + className: "col-12 mt-1", + children: /*#__PURE__*/_jsxs("div", { + className: "badge bg-warning-subtle text-dark border border-warning px-2.5 py-1 d-inline-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-info-circle-fill text-warning" + }), /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Challan Inward:" + }), " Adds physical stock immediately without ledger debt. This challan can later be imported directly into a final Tax Invoice."] + })] + }) + })] + }) + }), (!selectedSupplierId || !invoiceNo.trim()) && !editingPurchaseId ? /*#__PURE__*/_jsxs("div", { + className: "card border border-2 border-dashed bg-light text-center p-4 my-4", + style: { + borderRadius: '12px' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "mx-auto mb-2 text-primary", + style: { + width: '48px', + height: '48px', + borderRadius: '50%', + background: '#e0f2fe', + display: 'flex', + alignItems: 'center', + justifyContent: 'center' + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-up-circle fs-3" + }) + }), /*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-dark mb-1", + children: ["Step 1: Select Supplier & Enter ", isChallan ? 'Challan' : 'Invoice', " Details Above"] + }), /*#__PURE__*/_jsxs("p", { + className: "text-muted small mb-0", + style: { + maxWidth: '560px', + margin: '0 auto' + }, + children: ["Please choose the ", /*#__PURE__*/_jsx("strong", { + children: "Supplier / Distributor" + }), " and provide the ", /*#__PURE__*/_jsx("strong", { + children: isChallan ? 'Delivery Challan No.' : 'Supplier Bill / Invoice No.' + }), " above to unlock the medicine entry form, historical rate lookup, and pending challan imports."] + })] + }) : + /*#__PURE__*/ + /* Step 2: Main Pharma Entry Workstation (2-Column Grid) */ + _jsxs("div", { + className: "row g-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-xl-8 col-lg-7", + children: [/*#__PURE__*/_jsxs("div", { + className: "card border shadow-sm mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark small", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-list-check me-1 text-primary" + }), "Invoice Line Items (", rows.length, ")"] + }), rows.length > 0 && /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border", + children: ["Total Items: ", rows.length] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + style: { + maxHeight: '280px', + overflowY: 'auto' + }, + children: /*#__PURE__*/_jsxs("table", { + className: "table table-sm table-hover table-bordered mb-0 align-middle", + style: { + fontSize: '11.5px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light sticky-top", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: '30px' + }, + className: "text-center", + children: "#" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '50px' + }, + className: "text-center", + children: "RecNo" + }), /*#__PURE__*/_jsx("th", { + style: { + minWidth: '130px', + maxWidth: '160px' + }, + children: "Item Name" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '80px' + }, + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '65px' + }, + className: "text-center", + children: "Exp." + }), /*#__PURE__*/_jsx("th", { + style: { + width: '65px' + }, + className: "text-end", + children: "MRP" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '55px' + }, + className: "text-center", + children: "Qty." + }), /*#__PURE__*/_jsx("th", { + style: { + width: '65px' + }, + className: "text-end", + children: "Rate" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '75px' + }, + className: "text-end", + children: "Amount" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '50px' + }, + className: "text-end", + children: "Disc." + }), /*#__PURE__*/_jsx("th", { + style: { + width: '70px' + }, + className: "text-end", + children: "Tax Amount" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '60px' + }, + className: "text-end", + children: "CGST" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '60px' + }, + className: "text-end", + children: "SGST" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '80px' + }, + className: "text-end", + children: "Net Amount" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '60px' + }, + className: "text-center", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: rows.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "15", + className: "text-center text-muted py-4", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-inbox fs-4 d-block mb-1 text-secondary" + }), /*#__PURE__*/_jsx("span", { + children: "No medicines added yet. Use the form below or include pending challans from the right." + })] + }) + }) : rows.map((r, i) => { + const expDisplay = r.exp_month && r.exp_year ? `${r.exp_month}/${r.exp_year}` : r.expiry_date ? r.expiry_date.slice(2, 7) : '-'; + const taxAmt = ((Number(r.cgst_amount) || 0) + (Number(r.sgst_amount) || 0)).toFixed(2); + const isReturn = Number(r.qty_packs) < 0 || Number(r.net_amount) < 0; + return /*#__PURE__*/_jsxs("tr", { + className: editingItemIndex === i ? 'table-warning' : isReturn ? 'table-danger bg-danger-subtle' : '', + children: [/*#__PURE__*/_jsx("td", { + className: "text-center text-secondary", + children: i + 1 + }), /*#__PURE__*/_jsx("td", { + className: "text-center text-secondary", + children: r.item_id || r.product_master_id || i + 1 + }), /*#__PURE__*/_jsxs("td", { + style: { + maxWidth: '160px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("span", { + className: "fw-bold text-truncate text-dark", + title: r.item_name, + children: r.item_name + }), isReturn && /*#__PURE__*/_jsx("span", { + className: "badge bg-danger text-white py-0 px-1", + style: { + fontSize: '9px' + }, + children: "RETURN" + })] + }), r.generic_name && /*#__PURE__*/_jsx("div", { + className: "text-muted text-truncate", + style: { + fontSize: '10px' + }, + title: r.generic_name, + children: r.generic_name + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border font-monospace", + children: r.batch_no || '-' + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: expDisplay + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: ["₹", Number(r.mrp || 0).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-center", + children: [/*#__PURE__*/_jsx("span", { + className: `fw-bold ${isReturn ? 'text-danger' : ''}`, + children: r.qty_packs + }), Number(r.free_qty_packs) > 0 && /*#__PURE__*/_jsxs("span", { + className: "text-success", + style: { + fontSize: '10px' + }, + children: ["+", r.free_qty_packs, "F"] + })] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: ["₹", Number(r.ptr || 0).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: `text-end ${isReturn ? 'text-danger fw-semibold' : ''}`, + children: ["₹", Number(r.amount || 0).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: [Number(r.discount_pct || 0), "%"] + }), /*#__PURE__*/_jsxs("td", { + className: `text-end ${isReturn ? 'text-danger' : ''}`, + children: ["₹", taxAmt] + }), /*#__PURE__*/_jsxs("td", { + className: `text-end ${isReturn ? 'text-danger' : ''}`, + children: ["₹", Number(r.cgst_amount || Number(r.taxable_amount || 0) * (Number(r.cgst_pct || 6) / 100)).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: `text-end ${isReturn ? 'text-danger' : ''}`, + children: ["₹", Number(r.sgst_amount || Number(r.taxable_amount || 0) * (Number(r.sgst_pct || 6) / 100)).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: `text-end fw-bold ${isReturn ? 'text-danger' : 'text-dark'}`, + children: ["₹", Number(r.net_amount || 0).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-primary btn-sm py-0 px-1", + onClick: () => handleEditRow(i), + title: "Edit this row in form below", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-pencil" + }) + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-danger btn-sm py-0 px-1", + onClick: () => removeRow(i), + title: "Delete this row", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-trash" + }) + })] + }) + })] + }, i); + }) + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "card-footer bg-light py-2 px-3 d-flex flex-wrap justify-content-end align-items-center gap-4 text-secondary small fw-semibold", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted fw-normal", + children: "Total Taxable: " + }), /*#__PURE__*/_jsxs("strong", { + className: "text-dark fs-6", + children: ["₹", billTotals.taxable] + })] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted fw-normal", + children: "CGST: " + }), /*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: ["₹", billTotals.cgst] + })] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted fw-normal", + children: "SGST: " + }), /*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: ["₹", billTotals.sgst] + })] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted fw-normal", + children: "Net Amount: " + }), /*#__PURE__*/_jsxs("strong", { + className: "text-primary fs-5", + children: ["₹", billTotals.net] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border shadow-sm p-3 mb-3 bg-white", + style: { + borderRadius: '10px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle-dotted text-primary me-1" + }), editingItemIndex !== null ? `Modify Row #${editingItemIndex + 1}` : 'Add Medicine to Inward Bill'] + }), editingItemIndex !== null && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-link text-danger p-0 text-decoration-none", + onClick: resetItemForm, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " Cancel Row Edit"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-9 position-relative", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("span", { + children: ["Product Search (Master Auto-Search) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-link btn-sm p-0 text-decoration-none fw-semibold", + style: { + fontSize: '11px' + }, + onClick: () => openAddMasterModal(itemForm.item_name), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle me-1" + }), "+ Add to Master"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "text", + id: "pharma_product_search_input", + className: `form-control form-control-sm fw-semibold ${itemForm.item_id ? 'border-success' : ''}`, + placeholder: "Type medicine name (e.g. ACEFE-P, Augmentin)...", + value: itemForm.item_name, + autoComplete: "off", + onChange: e => handleProductSearchChange(e.target.value), + onKeyDown: handleProductSearchKeyDown, + onFocus: () => { + if (itemForm.item_name.trim().length >= 1) { + handleProductSearchChange(itemForm.item_name); + } + } + }), itemForm.item_id > 0 && /*#__PURE__*/_jsx("span", { + className: "input-group-text bg-success text-white py-0 px-2", + title: "Matched in Master Catalog", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-check2" + }) + })] + }), itemForm.generic_name ? /*#__PURE__*/_jsxs("div", { + className: "text-muted text-truncate mt-1 d-flex align-items-center gap-1", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-light text-primary border", + style: { + fontSize: '9.5px' + }, + children: itemForm.category || 'Tablet' + }), /*#__PURE__*/_jsx("span", { + children: itemForm.generic_name + })] + }) : null, activeSearchRow && /*#__PURE__*/_jsxs("div", { + ref: suggestionsDropdownRef, + className: "shadow-lg border rounded-2 bg-white", + style: { + position: 'absolute', + top: '100%', + left: 0, + width: '100%', + maxHeight: '280px', + overflowY: 'auto', + zIndex: 1060, + marginTop: '2px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "bg-light px-2.5 py-1.5 border-bottom d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsx("span", { + className: "small fw-bold text-secondary", + style: { + fontSize: '11px' + }, + children: isSearchingMeds ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split spinner-border spinner-border-sm me-1" + }), "Searching master..."] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-database-check me-1 text-primary" + }), "Pharmacy Master (", suggestions.length, " found)", suggestions.length > 0 && /*#__PURE__*/_jsx("span", { + className: "text-muted ms-2 fw-normal", + style: { + fontSize: '10px' + }, + children: "(Use ↑ ↓ & Enter)" + })] + }) + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close", + style: { + fontSize: '9px' + }, + onClick: () => { + setActiveSearchRow(false); + setSelectedSuggestionIndex(-1); + } + })] + }), suggestions.length > 0 ? suggestions.map((sug, sIdx) => { + const isSelected = sIdx === selectedSuggestionIndex; + return /*#__PURE__*/_jsxs("div", { + ref: isSelected ? activeSuggestionRef : null, + className: `p-2 border-bottom ${isSelected ? 'bg-primary-subtle' : 'hover-bg-light'}`, + style: { + cursor: 'pointer', + transition: 'all 0.12s ease', + borderLeft: isSelected ? '4px solid #0284c7' : '4px solid transparent', + backgroundColor: isSelected ? '#e0f2fe' : undefined + }, + onMouseEnter: () => setSelectedSuggestionIndex(sIdx), + onMouseDown: e => { + e.preventDefault(); + handleSelectMedicine(sug); + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("span", { + className: `text-dark ${isSelected ? 'fw-bold text-primary' : 'fw-semibold'}`, + style: { + fontSize: '12.5px' + }, + children: [isSelected && /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-right-short text-primary me-1" + }), sug.item_name] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [isSelected && /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary text-white", + style: { + fontSize: '9px', + fontWeight: 600 + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-return-left me-1" + }), "Enter"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-primary border", + style: { + fontSize: '10px' + }, + children: sug.category || 'Tablet' + })] + })] + }), sug.generic_name && /*#__PURE__*/_jsx("div", { + className: "text-muted text-truncate small", + style: { + fontSize: '11px' + }, + children: sug.generic_name + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2 mt-1 align-items-center", + style: { + fontSize: '10.5px' + }, + children: [/*#__PURE__*/_jsxs("span", { + className: "text-secondary", + children: ["Pack: ", /*#__PURE__*/_jsxs("strong", { + children: [sug.units_per_pack || 10, "s"] + })] + }), /*#__PURE__*/_jsxs("span", { + className: "text-secondary", + children: ["GST: ", /*#__PURE__*/_jsxs("strong", { + children: [sug.gst_rate, "%"] + })] + }), /*#__PURE__*/_jsxs("span", { + className: "text-secondary", + children: ["HSN: ", /*#__PURE__*/_jsx("strong", { + children: sug.hsn_code || '3004' + })] + }), sug.mrp ? /*#__PURE__*/_jsxs("span", { + className: "text-secondary", + children: ["MRP: ", /*#__PURE__*/_jsxs("strong", { + children: ["₹", sug.mrp] + })] + }) : null] + })] + }, sIdx); + }) : !isSearchingMeds && /*#__PURE__*/_jsxs("div", { + className: "p-3 text-center text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-search fs-4 d-block mb-1 text-secondary" + }), /*#__PURE__*/_jsxs("div", { + className: "small fw-semibold", + children: ["No medicine found matching \"", itemForm.item_name, "\""] + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '11px' + }, + children: "Click below to add it directly into Pharmacy Master" + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-2 bg-light border-top text-center", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary w-100 fw-bold py-1", + style: { + fontSize: '12px' + }, + onMouseDown: e => { + e.preventDefault(); + openAddMasterModal(itemForm.item_name); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle-fill me-1" + }), "+ Add \"", itemForm.item_name || 'New Medicine', "\" in Master"] + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Product Code" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-light text-secondary font-monospace", + value: itemForm.product_master_id || itemForm.item_id || 'AUTO', + readOnly: true + })] + })] + }), itemForm.item_id > 0 || editingItemIndex !== null ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between bg-primary-subtle border border-primary-subtle px-2.5 py-1 rounded mb-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "small text-primary fw-semibold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-1 text-success" + }), editingItemIndex !== null ? `Editing: ${itemForm.item_name}` : `Selected: ${itemForm.item_name} (Auto-filled with last batch, rate & location)`] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-link btn-sm p-0 text-danger text-decoration-none fw-semibold", + style: { + fontSize: '11px' + }, + onClick: () => resetItemForm(true), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " Change Product"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Packaging" + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: "pharma_packaging_input", + className: "form-control form-control-sm", + placeholder: "10", + value: itemForm.units_per_pack, + onChange: e => handleItemFormChange('units_per_pack', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_batch_no_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Batch No. ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + id: "pharma_batch_no_input", + className: "form-control form-control-sm text-uppercase font-monospace fw-bold", + placeholder: "e.g. B-902", + value: itemForm.batch_no, + onChange: e => handleItemFormChange('batch_no', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_exp_month_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Exp. Month" + }), /*#__PURE__*/_jsx("select", { + id: "pharma_exp_month_input", + className: "form-select form-select-sm", + value: itemForm.exp_month, + onChange: e => handleItemFormChange('exp_month', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_exp_year_input'), + children: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'].map(m => /*#__PURE__*/_jsxs("option", { + value: m, + children: [m, " (", ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][parseInt(m) - 1], ")"] + }, m)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Exp. Year" + }), /*#__PURE__*/_jsx("select", { + id: "pharma_exp_year_input", + className: "form-select form-select-sm", + value: itemForm.exp_year, + onChange: e => handleItemFormChange('exp_year', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_mrp_input'), + children: ['24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36'].map(y => /*#__PURE__*/_jsxs("option", { + value: y, + children: ["20", y] + }, y)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "MRP (₹)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + id: "pharma_mrp_input", + className: "form-control form-control-sm", + placeholder: "0.00", + value: itemForm.mrp, + onChange: e => handleItemFormChange('mrp', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_qty_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-0", + children: ["Qty (Packs) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), Number(itemForm.qty_packs) < 0 && /*#__PURE__*/_jsx("span", { + className: "badge bg-danger text-white py-0 px-1", + style: { + fontSize: '9px' + }, + children: "RETURN" + })] + }), /*#__PURE__*/_jsx("input", { + type: "number", + id: "pharma_qty_input", + className: `form-control form-control-sm fw-bold ${Number(itemForm.qty_packs) < 0 ? 'text-danger border-danger bg-danger-subtle' : ''}`, + placeholder: "Qty (+ In / - Ret)", + value: itemForm.qty_packs, + onChange: e => handleItemFormChange('qty_packs', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_free_qty_input') + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Free Qty" + }), /*#__PURE__*/_jsx("input", { + type: "number", + min: "0", + id: "pharma_free_qty_input", + className: "form-control form-control-sm", + value: itemForm.free_qty_packs, + onChange: e => handleItemFormChange('free_qty_packs', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_ptr_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Purchase Rate (PTR)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + id: "pharma_ptr_input", + className: "form-control form-control-sm", + placeholder: "0.00", + value: itemForm.ptr, + onChange: e => handleItemFormChange('ptr', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_disc_pct_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Amount" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-light text-secondary fw-semibold", + value: '₹' + Number(itemForm.amount || 0).toFixed(2), + readOnly: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Discount %" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + min: "0", + max: "100", + id: "pharma_disc_pct_input", + className: "form-control form-control-sm", + value: itemForm.discount_pct, + onChange: e => handleItemFormChange('discount_pct', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'submit') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "SCH Amount" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + min: "0", + id: "pharma_sch_amount_input", + className: "form-control form-control-sm", + value: itemForm.sch_disc_amount, + onChange: e => handleItemFormChange('sch_disc_amount', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_sch_disc_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "SCH Discount %" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + min: "0", + max: "100", + id: "pharma_sch_disc_input", + className: "form-control form-control-sm", + value: itemForm.sch_disc_pct, + onChange: e => handleItemFormChange('sch_disc_pct', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'submit') + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Taxable Amount" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-light text-secondary fw-semibold", + value: '₹' + Number(itemForm.taxable_amount || 0).toFixed(2), + readOnly: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "CGST %" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: itemForm.cgst_pct, + onChange: e => { + const val = parseFloat(e.target.value) || 0; + handleItemFormChange('cgst_pct', val); + handleItemFormChange('sgst_pct', val); + }, + children: [/*#__PURE__*/_jsx("option", { + value: "0", + children: "0% (Nil / Exempt)" + }), /*#__PURE__*/_jsx("option", { + value: "2.5", + children: "2.5% (5% GST)" + }), /*#__PURE__*/_jsx("option", { + value: "9", + children: "9.0% (18% GST)" + }), /*#__PURE__*/_jsx("option", { + value: "20", + children: "20.0% (40% GST)" + }), /*#__PURE__*/_jsx("option", { + value: "6", + children: "6.0% (12% Legacy)" + }), /*#__PURE__*/_jsx("option", { + value: "14", + children: "14.0% (28% Legacy)" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "SGST / IGST %" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: itemForm.sgst_pct, + onChange: e => handleItemFormChange('sgst_pct', parseFloat(e.target.value) || 0), + children: [/*#__PURE__*/_jsx("option", { + value: "0", + children: "0% (Nil / Exempt)" + }), /*#__PURE__*/_jsx("option", { + value: "2.5", + children: "2.5% (5% GST)" + }), /*#__PURE__*/_jsx("option", { + value: "9", + children: "9.0% (18% GST)" + }), /*#__PURE__*/_jsx("option", { + value: "20", + children: "20.0% (40% GST)" + }), /*#__PURE__*/_jsx("option", { + value: "6", + children: "6.0% (12% Legacy)" + }), /*#__PURE__*/_jsx("option", { + value: "14", + children: "14.0% (28% Legacy)" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Net Amount" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-primary-subtle text-primary fw-bold", + value: '₹' + Number(itemForm.net_amount || 0).toFixed(2), + readOnly: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Selling Price" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + id: "pharma_selling_price_input", + className: "form-control form-control-sm", + placeholder: "MRP", + value: itemForm.selling_price, + onChange: e => handleItemFormChange('selling_price', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_shelf_no_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "HSNCODE" + }), /*#__PURE__*/_jsx("input", { + type: "text", + id: "pharma_hsn_input", + className: "form-control form-control-sm", + value: itemForm.hsn_code, + onChange: e => handleItemFormChange('hsn_code', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_shelf_no_input') + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 align-items-end", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-3 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Storage" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: itemForm.storage_type, + onChange: e => handleItemFormChange('storage_type', e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "Normal", + children: "Normal" + }), /*#__PURE__*/_jsx("option", { + value: "Cold Storage", + children: "Cold Storage (2-8°C)" + }), /*#__PURE__*/_jsx("option", { + value: "Cool", + children: "Cool (8-15°C)" + }), /*#__PURE__*/_jsx("option", { + value: "Deep Freeze", + children: "Deep Freeze (-20°C)" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Shelf No." + }), /*#__PURE__*/_jsx("input", { + type: "text", + id: "pharma_shelf_no_input", + className: "form-control form-control-sm", + placeholder: "e.g. S-1", + value: itemForm.shelf_no, + onChange: e => handleItemFormChange('shelf_no', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'pharma_rack_no_input') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-2 col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Rack No." + }), /*#__PURE__*/_jsx("input", { + type: "text", + id: "pharma_rack_no_input", + className: "form-control form-control-sm", + placeholder: "e.g. R-10", + value: itemForm.rack_no, + onChange: e => handleItemFormChange('rack_no', e.target.value), + onKeyDown: e => handleFieldKeyDown(e, 'submit') + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-5 col-12 d-flex gap-2 justify-content-end mt-2 mt-md-0", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm px-3", + onClick: () => resetItemForm(true), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-counterclockwise me-1" + }), " Clear"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + id: "pharma_add_stock_btn", + className: editingItemIndex !== null ? "btn btn-warning text-dark fw-bold btn-sm px-3 shadow-sm" : Number(itemForm.qty_packs) < 0 ? "btn btn-danger fw-bold btn-sm px-4 shadow-sm" : "btn btn-primary fw-bold btn-sm px-4 shadow-sm", + onClick: handleAddOrUpdateItem, + title: Number(itemForm.qty_packs) < 0 ? "Add Return / Debit Item (Press Ctrl+Enter anytime)" : "Add Stock (Press Ctrl+Enter anytime)", + children: [/*#__PURE__*/_jsx("i", { + className: editingItemIndex !== null ? "bi bi-check2-circle me-1" : Number(itemForm.qty_packs) < 0 ? "bi bi-dash-circle me-1" : "bi bi-plus-circle me-1" + }), editingItemIndex !== null ? 'Update Stock Item' : Number(itemForm.qty_packs) < 0 ? '⊖ Add Return Item' : '+ Add Stock', /*#__PURE__*/_jsx("span", { + className: "badge bg-white bg-opacity-25 ms-1.5 py-0.5 px-1.5 text-white", + style: { + fontSize: '10px' + }, + children: "Ctrl+↵" + })] + })] + })] + })] + }) : /*#__PURE__*/_jsxs("div", { + className: "text-center py-4 text-muted small bg-light rounded-2 border border-dashed mt-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-search text-primary me-1.5 fs-5 d-block mb-1" + }), /*#__PURE__*/_jsxs("span", { + children: ["Search and select a medicine in ", /*#__PURE__*/_jsx("strong", { + children: "Product Search" + }), " above to enter stock details and auto-fill last batch, expiry, MRP, rate & rack location."] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center p-3 bg-light rounded-3 border", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted small", + children: "Ready to commit to inventory:" + }), /*#__PURE__*/_jsxs("div", { + className: "fw-bold text-dark", + children: [rows.length, " ", rows.length === 1 ? 'medicine' : 'medicines', " | Net Payable: ", /*#__PURE__*/_jsxs("span", { + className: "text-primary fs-6", + children: ["₹", billTotals.net] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [editingPurchaseId && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm px-3", + onClick: cancelEditPurchase, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " Cancel Edit"] + }), /*#__PURE__*/_jsxs("button", { + className: editingPurchaseId ? "btn btn-warning shadow-sm fw-bold px-3 py-2 text-dark" : isChallan ? "btn btn-warning fw-bold text-dark shadow-sm px-4 py-2" : "btn btn-success-custom shadow-sm px-4 py-2", + onClick: savePurchaseBill, + children: [/*#__PURE__*/_jsx("i", { + className: editingPurchaseId ? "bi bi-check2-all me-1" : isChallan ? "bi bi-truck me-1" : "bi bi-check-circle me-1" + }), editingPurchaseId ? `Update Purchase Invoice #${invoiceNo}` : isChallan ? 'Record Delivery Challan & Update Stock' : 'Record Inward Bill & Update Inventory'] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-xl-4 col-lg-5", + children: [/*#__PURE__*/_jsxs("div", { + className: "card border shadow-sm mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark small", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-truck text-warning me-1" + }), "Pending Delivery Challans"] + }), selectedSupplierId && /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-link p-0 text-decoration-none", + onClick: () => fetchSupplierChallans(selectedSupplierId), + title: "Refresh supplier challans", + children: /*#__PURE__*/_jsx("i", { + className: `bi bi-arrow-repeat ${isLoadingChallans ? 'spinner-border spinner-border-sm' : ''}` + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "card-body p-2", + style: { + maxHeight: '280px', + overflowY: 'auto' + }, + children: !selectedSupplierId ? /*#__PURE__*/_jsx("div", { + className: "text-muted small p-3 text-center bg-light rounded", + children: "Select a supplier above to view pending challans." + }) : isLoadingChallans ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-3 text-muted small", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary me-2" + }), "Loading supplier challans..."] + }) : supplierChallans.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "text-muted small p-3 text-center bg-light rounded", + children: "No challan items available for this supplier." + }) : supplierChallans.map((ch, chIdx) => /*#__PURE__*/_jsxs("div", { + className: "border rounded-2 p-2 mb-2 bg-light", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1.5 pb-1 border-bottom", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("strong", { + className: "text-dark", + style: { + fontSize: '12px' + }, + children: ["Challan #", ch.challan_no] + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted", + style: { + fontSize: '10.5px' + }, + children: ["Date: ", ch.date || 'N/A', " • ", ch.items ? ch.items.length : 0, " items"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-primary py-0.5 px-2", + style: { + fontSize: '11px' + }, + onClick: () => includeAllChallanItems(ch), + title: "Import all items from this challan into invoice", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-right me-1" + }), " Include All"] + })] + }), ch.items && ch.items.length > 0 ? /*#__PURE__*/_jsx("div", { + className: "d-flex flex-column gap-1", + children: ch.items.map((ci, cItemIdx) => /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center bg-white p-1.5 rounded border", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "text-truncate me-2", + style: { + maxWidth: '170px' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold text-dark text-truncate", + children: ci.item_name + }), /*#__PURE__*/_jsxs("span", { + className: "text-muted font-monospace", + style: { + fontSize: '10px' + }, + children: ["Batch: ", ci.batch_no || '-', " | Qty: ", ci.qty_packs] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-primary py-0 px-1.5 text-nowrap", + style: { + fontSize: '10.5px' + }, + onClick: () => includeChallanItem(ch, ci), + title: "Import this item into invoice", + children: "+ Include" + })] + }, cItemIdx)) + }) : /*#__PURE__*/_jsx("div", { + className: "text-muted small", + style: { + fontSize: '11px' + }, + children: "No items found in this challan." + })] + }, chIdx)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border shadow-sm", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark small", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history text-info me-1" + }), "Previous Purchase History"] + }), historyTargetItemName && /*#__PURE__*/_jsx("span", { + className: "badge bg-info-subtle text-info border text-truncate", + style: { + maxWidth: '140px', + fontSize: '10.5px' + }, + children: historyTargetItemName + })] + }), /*#__PURE__*/_jsx("div", { + className: "card-body p-2", + style: { + maxHeight: '310px', + overflowY: 'auto' + }, + children: isLoadingProductHistory ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-3 text-muted small", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-info me-2" + }), "Fetching purchase rate history..."] + }) : !historyTargetItemName && productHistory.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "text-muted small p-3 text-center bg-light rounded", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-search d-block mb-1 fs-5 text-secondary" + }), "Type or select a product in ", /*#__PURE__*/_jsx("strong", { + children: "Product Search" + }), " to check previous purchase prices & vendors."] + }) : productHistory.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "text-muted small p-3 text-center bg-light rounded", + children: "No purchase history found for selected product." + }) : /*#__PURE__*/_jsx("div", { + className: "d-flex flex-column gap-2", + children: productHistory.map((ph, phIdx) => /*#__PURE__*/_jsxs("div", { + className: "p-2 border rounded-2 bg-light", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("strong", { + className: "text-primary text-truncate", + style: { + maxWidth: '160px' + }, + children: ph.supplier_name || 'Distributor' + }), /*#__PURE__*/_jsx("span", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: ph.invoice_date || ph.created_at ? (ph.invoice_date || ph.created_at).slice(0, 10) : '' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between text-secondary mb-1", + style: { + fontSize: '10.5px' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: ["Inv: ", /*#__PURE__*/_jsx("strong", { + children: ph.supplier_invoice_no || '-' + })] + }), /*#__PURE__*/_jsxs("span", { + children: ["Batch: ", /*#__PURE__*/_jsx("span", { + className: "font-monospace", + children: ph.batch_no || '-' + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center pt-1 border-top mt-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "PTR: " + }), /*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: ["₹", Number(ph.ptr || 0).toFixed(2)] + }), ph.mrp ? /*#__PURE__*/_jsxs("span", { + className: "text-muted ms-2", + children: ["MRP: ₹", Number(ph.mrp).toFixed(2)] + }) : null, Number(ph.discount_pct) > 0 ? /*#__PURE__*/_jsxs("span", { + className: "text-success ms-1", + children: ["(-", ph.discount_pct, "%)"] + }) : null] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-info py-0 px-1.5", + style: { + fontSize: '10.5px' + }, + onClick: () => { + setItemForm(prev => recomputeItemForm({ + ...prev, + ptr: ph.ptr || prev.ptr, + mrp: ph.mrp || prev.mrp, + discount_pct: ph.discount_pct !== undefined ? ph.discount_pct : prev.discount_pct, + gst_rate: ph.gst_rate !== undefined ? ph.gst_rate : prev.gst_rate, + cgst_pct: (Number(ph.gst_rate) || 12) / 2, + sgst_pct: (Number(ph.gst_rate) || 12) / 2 + })); + notify(`Applied historical PTR ₹${ph.ptr} to entry form.`, 'info'); + }, + title: "Apply these purchase rates to current item form", + children: "Use Rate" + })] + })] + }, phIdx)) + }) + })] + })] + })] + })] + }), subTab === 'excel' && /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold text-success mb-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-spreadsheet me-1" + }), " Excel / CSV Inventory Importer"] + }), /*#__PURE__*/_jsxs("p", { + className: "text-muted small mb-3", + children: ["Upload your stock export from Microsoft Excel or CSV format to seamlessly import medicines, batch numbers, MRP, PTR, HSN codes, and opening stock into ", /*#__PURE__*/_jsx("strong", { + children: store.store_name + }), "."] + }), /*#__PURE__*/_jsxs("div", { + className: "p-4 bg-light rounded-3 border text-center mb-3", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cloud-arrow-up fs-1 text-success d-block mb-2" + }), /*#__PURE__*/_jsx("h6", { + className: "fw-bold", + children: "Upload CSV / Excel File" + }), /*#__PURE__*/_jsx("p", { + className: "small text-muted mb-3", + children: "Ensure file is formatted as standard CSV or Excel-exported CSV." + }), /*#__PURE__*/_jsx("input", { + type: "file", + id: "excel_file_input", + accept: ".csv, .txt", + className: "form-control form-control-sm w-50 mx-auto mb-3" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success-custom", + onClick: async () => { + const fileInput = document.getElementById('excel_file_input'); + if (!fileInput.files || fileInput.files.length === 0) { + alert('Please select a CSV file first.'); + return; + } + const formData = new FormData(); + formData.append('store_id', store.store_id); + formData.append('import_file', fileInput.files[0]); + try { + const res = await fetch(API_BASE + 'stock/import-excel', { + method: 'POST', + body: formData + }); + const data = await res.json(); + if (data.ok) { + alert(data.message); + fileInput.value = ''; + } else { + alert(data.error || 'Import failed.'); + } + } catch (e) { + alert('Import error: ' + e.message); + } + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-upload me-1" + }), " Import Inventory into ", store.store_name] + })] + })] + }), subTab === 'suppliers' && /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold mb-0 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-truck text-primary me-1" + }), " Approved Drug Distributors & Suppliers"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Manage licensed pharmaceutical distributors, DL Form 20B/21B, GSTIN, and credit terms" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + style: { + width: 250 + }, + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white border-end-0", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search text-muted" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control border-start-0", + placeholder: "Search distributor, GST...", + value: supplierSearch, + onChange: e => setSupplierSearch(e.target.value) + }), supplierSearch && /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary", + type: "button", + onClick: () => setSupplierSearch(''), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-primary btn-sm px-3", + onClick: openAddSupplier, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle me-1" + }), " Add New Supplier"] + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 45 + }, + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Distributor Name" + }), /*#__PURE__*/_jsx("th", { + children: "DL Form 20B / 21B" + }), /*#__PURE__*/_jsx("th", { + children: "GSTIN & PAN" + }), /*#__PURE__*/_jsx("th", { + children: "Phone / Contact" + }), /*#__PURE__*/_jsx("th", { + children: "Credit Terms" + }), /*#__PURE__*/_jsx("th", { + children: "Address / Bank" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 90 + }, + className: "text-end pe-3", + children: "Actions" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: filteredSuppliers.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-truck fs-2 d-block mb-1 text-secondary" + }), suppliers.length === 0 ? 'No distributors registered yet. Click "Add New Supplier" to create one.' : 'No suppliers match your search query.'] + }) + }) : filteredSuppliers.map((s, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-semibold text-secondary", + children: i + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark fs-6", + children: s.supplier_name + }), s.email && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-envelope me-1" + }), s.email] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + className: "small", + children: [/*#__PURE__*/_jsx("strong", { + children: "20B:" + }), " ", s.dl_no_20b || /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "N/A" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "small", + children: [/*#__PURE__*/_jsx("strong", { + children: "21B:" + }), " ", s.dl_no_21b || /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "N/A" + })] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + children: /*#__PURE__*/_jsx("code", { + className: "text-primary fw-bold", + children: s.gstin || 'N/A' + }) + }), s.pan_no && /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + children: ["PAN: ", s.pan_no] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold text-dark", + children: s.phone || 'N/A' + }), s.contact_person && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person me-1" + }), s.contact_person] + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border px-2 py-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-check me-1 text-primary" + }), s.credit_days || 30, " Days"] + }) + }), /*#__PURE__*/_jsxs("td", { + style: { + maxWidth: 220 + }, + children: [s.address && /*#__PURE__*/_jsxs("div", { + className: "small text-truncate", + title: s.address, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-geo-alt me-1 text-muted" + }), s.address] + }), s.bank_details && /*#__PURE__*/_jsxs("div", { + className: "small text-muted text-truncate", + title: s.bank_details, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-bank me-1" + }), s.bank_details] + }), !s.address && !s.bank_details && /*#__PURE__*/_jsx("span", { + className: "text-muted small", + children: "-" + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-end pe-3", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-outline-primary py-0.5 px-2", + title: "Edit Supplier", + onClick: () => openEditSupplier(s), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square" + }) + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-danger py-0.5 px-2", + title: "Remove Supplier", + onClick: () => handleDeleteSupplier(s.supplier_id, s.supplier_name), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-trash" + }) + })] + }) + })] + }, s.supplier_id)) + })] + }) + })] + }), subTab === 'ledger' && /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-4", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-3", + children: /*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 bg-white h-100 border-start border-4 border-primary", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-semibold text-uppercase", + style: { + fontSize: '11px' + }, + children: "Total Inward Purchases" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-dark mb-0 mt-1", + children: ["₹", Number(ledgerOverall.total_purchases || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "bg-primary-subtle text-primary p-2.5 rounded-circle", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-down fs-4" + }) + })] + }) + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3", + children: /*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 bg-white h-100 border-start border-4 border-success", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-semibold text-uppercase", + style: { + fontSize: '11px' + }, + children: "Total Payments Settled" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-success mb-0 mt-1", + children: ["₹", Number(ledgerOverall.total_paid || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "bg-success-subtle text-success p-2.5 rounded-circle", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-check2-circle fs-4" + }) + })] + }) + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3", + children: /*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 bg-white h-100 border-start border-4 border-danger", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-semibold text-uppercase", + style: { + fontSize: '11px' + }, + children: "Balance Outstanding" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-danger mb-0 mt-1", + children: ["₹", Number(ledgerOverall.outstanding_balance || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "bg-danger-subtle text-danger p-2.5 rounded-circle", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-octagon fs-4" + }) + })] + }) + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3", + children: /*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 bg-white h-100 border-start border-4 border-warning", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-semibold text-uppercase", + style: { + fontSize: '11px' + }, + children: "Pending Invoices" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-warning-emphasis mb-0 mt-1", + children: [ledgerOverall.total_pending_bills || 0, " Bills"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "bg-warning-subtle text-warning-emphasis p-2.5 rounded-circle", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-receipt fs-4" + }) + })] + }) + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3 bg-light p-2.5 rounded-3 border", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2 flex-grow-1", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-0 text-nowrap", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-funnel me-1" + }), "Select Supplier:"] + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + style: { + maxWidth: 320 + }, + value: activeLedgerSupplierId, + onChange: e => { + const val = e.target.value; + setActiveLedgerSupplierId(val); + if (val) fetchSupplierLedger(val);else setActiveLedgerDetail(null); + }, + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "-- All Suppliers Summary --" + }), suppliers.map(s => /*#__PURE__*/_jsx("option", { + value: s.supplier_id, + children: s.supplier_name + }, s.supplier_id))] + }), activeLedgerSupplierId && /*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-secondary btn-sm", + onClick: () => { + setActiveLedgerSupplierId(''); + setActiveLedgerDetail(null); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), " View All"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-success btn-sm shadow-sm fw-semibold", + onClick: () => openPaymentModal(activeLedgerSupplierId), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-stack me-1" + }), " Record Supplier Payment"] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-primary btn-sm", + onClick: () => { + fetchLedgerSummary(); + if (activeLedgerSupplierId) fetchSupplierLedger(activeLedgerSupplierId); + }, + title: "Refresh Ledger Data", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }) + })] + })] + }), !activeLedgerSupplierId && /*#__PURE__*/_jsx("div", { + className: "table-responsive shadow-sm rounded border", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 45 + }, + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Distributor / Agency" + }), /*#__PURE__*/_jsx("th", { + children: "GSTIN & Phone" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Total Purchases" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Total Paid" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Outstanding Due" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Pending Bills" + }), /*#__PURE__*/_jsx("th", { + className: "text-end pe-3", + children: "Actions" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: isLoadingLedger ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "8", + className: "text-center py-4", + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-2" + }), "Loading ledger summary..."] + }) + }) : ledgerSummary.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No suppliers found." + }) + }) : ledgerSummary.map((sup, idx) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "text-muted fw-semibold", + children: idx + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: sup.supplier_name + }), sup.contact_person && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person me-1" + }), sup.contact_person] + })] + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + children: /*#__PURE__*/_jsx("code", { + className: "text-primary fw-semibold", + children: sup.gstin || 'No GSTIN' + }) + }), sup.phone && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-1" + }), sup.phone] + })] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-semibold", + children: ["₹", Number(sup.total_purchases || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-success fw-semibold", + children: ["₹", Number(sup.total_paid || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-end", + children: /*#__PURE__*/_jsxs("span", { + className: `badge ${sup.outstanding_balance > 0 ? 'bg-danger-subtle text-danger border border-danger-subtle fs-6' : 'bg-success-subtle text-success border border-success-subtle'} px-2.5 py-1.5`, + children: ["₹", Number(sup.outstanding_balance || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: sup.pending_invoices > 0 ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning text-dark border border-warning px-2 py-1", + children: [sup.pending_invoices, " Unpaid"] + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-muted border px-2 py-1", + children: "All Settled" + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end pe-3", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-primary", + onClick: () => { + setActiveLedgerSupplierId(String(sup.supplier_id)); + fetchSupplierLedger(sup.supplier_id); + }, + title: "View detailed ledger statement", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-text me-1" + }), " Statement"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-success", + onClick: () => openPaymentModal(sup.supplier_id), + title: "Record payment against this supplier", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-credit-card me-1" + }), " Pay"] + })] + }) + })] + }, sup.supplier_id)) + })] + }) + }), activeLedgerSupplierId && activeLedgerDetail && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 mb-3 bg-white border-start border-4 border-primary", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold text-dark mb-1 d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-building text-primary" + }), activeLedgerDetail.supplier.supplier_name] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-3 text-muted small", + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "GSTIN:" + }), " ", activeLedgerDetail.supplier.gstin || 'N/A'] + }), /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "DL No:" + }), " ", activeLedgerDetail.supplier.dl_no_20b || activeLedgerDetail.supplier.dl_no_21b || 'N/A'] + }), /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Phone:" + }), " ", activeLedgerDetail.supplier.phone || 'N/A'] + }), /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("strong", { + children: "Credit Days:" + }), " ", activeLedgerDetail.supplier.credit_days || 30, " Days"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted text-uppercase d-block", + style: { + fontSize: '11px' + }, + children: "Net Outstanding Balance" + }), /*#__PURE__*/_jsxs("span", { + className: `badge ${activeLedgerDetail.summary.outstanding_balance > 0 ? 'bg-danger text-white fs-5' : 'bg-success text-white fs-5'} px-3 py-2`, + children: ["₹", Number(activeLedgerDetail.summary.outstanding_balance || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-dark mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split text-warning me-1" + }), " Pending Invoices (", activeLedgerDetail.pending_invoices?.length || 0, ")"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Invoices awaiting full or partial payment" + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover align-middle mb-0", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Bill / Invoice No" + }), /*#__PURE__*/_jsx("th", { + children: "Invoice Date" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Bill Amount" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Paid Amount" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Pending Amount" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-end pe-3", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: !activeLedgerDetail.pending_invoices || activeLedgerDetail.pending_invoices.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "7", + className: "text-center py-3 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-all text-success me-1" + }), "All purchase bills for this supplier are fully paid."] + }) + }) : activeLedgerDetail.pending_invoices.map(inv => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-bold text-primary", + children: inv.supplier_invoice_no + }), /*#__PURE__*/_jsx("td", { + children: inv.invoice_date + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-semibold", + children: ["₹", Number(inv.net_amount).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-success", + children: ["₹", Number(inv.paid_amount).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold text-danger", + children: ["₹", Number(inv.pending_amount).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsx("span", { + className: `badge ${inv.payment_status === 'partially_paid' ? 'bg-warning text-dark' : 'bg-danger'} px-2 py-1`, + children: inv.payment_status === 'partially_paid' ? 'Partially Paid' : 'Unpaid' + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end pe-3", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-primary py-1 px-2 shadow-sm", + onClick: () => loadPurchaseForEdit(inv.purchase_id), + title: "Edit this Purchase Invoice", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square me-1" + }), " Edit"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success py-1 px-2.5 shadow-sm fw-semibold", + onClick: () => openPaymentModal(activeLedgerDetail.supplier.supplier_id, inv.purchase_id, inv.pending_amount), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash me-1" + }), " Pay Bill"] + })] + }) + })] + }, inv.purchase_id)) + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header bg-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-dark mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-check text-primary me-1" + }), " Complete Ledger Statement & Running Balance"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border px-2 py-1", + children: ["Total Transactions: ", activeLedgerDetail.statement?.length || 0] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-bordered table-hover align-middle mb-0", + style: { + fontSize: '12.5px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 100 + }, + children: "Date" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 130 + }, + children: "Voucher / Ref" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 100 + }, + children: "Type" + }), /*#__PURE__*/_jsx("th", { + children: "Particulars & Details" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 120 + }, + children: "Debit (₹ Payments)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 120 + }, + children: "Credit (₹ Inward)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 140 + }, + children: "Balance (₹ Payable)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: !activeLedgerDetail.statement || activeLedgerDetail.statement.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "7", + className: "text-center py-4 text-muted", + children: "No transactions recorded for this supplier." + }) + }) : activeLedgerDetail.statement.map((row, idx) => /*#__PURE__*/_jsxs("tr", { + className: row.type === 'PAYMENT' ? 'table-success-subtle' : '', + children: [/*#__PURE__*/_jsx("td", { + className: "text-nowrap", + children: row.date + }), /*#__PURE__*/_jsx("td", { + className: "fw-semibold text-primary", + children: row.type === 'INVOICE' && row.invoice_id ? /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-link p-0 text-decoration-none fw-bold text-primary", + onClick: () => loadPurchaseForEdit(row.invoice_id), + title: "Click to edit purchase invoice", + children: [row.voucher_no, " ", /*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square text-muted ms-1", + style: { + fontSize: '11px' + } + })] + }) : row.voucher_no + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge ${row.type === 'INVOICE' ? 'bg-primary-subtle text-primary border border-primary-subtle' : 'bg-success text-white'}`, + children: row.type === 'INVOICE' ? 'Purchase Bill' : 'Payment' + }) + }), /*#__PURE__*/_jsx("td", { + children: row.particulars + }), /*#__PURE__*/_jsx("td", { + className: "text-end text-success fw-bold", + children: row.debit > 0 ? '₹' + Number(row.debit).toFixed(2) : '-' + }), /*#__PURE__*/_jsx("td", { + className: "text-end text-dark fw-bold", + children: row.credit > 0 ? '₹' + Number(row.credit).toFixed(2) : '-' + }), /*#__PURE__*/_jsx("td", { + className: "text-end fw-bold", + children: /*#__PURE__*/_jsxs("span", { + className: row.balance > 0 ? 'text-danger' : 'text-success', + children: ["₹", Number(row.balance).toFixed(2)] + }) + })] + }, idx)) + }), activeLedgerDetail.statement?.length > 0 && /*#__PURE__*/_jsx("tfoot", { + className: "table-light fw-bold", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + colSpan: "4", + className: "text-end", + children: "Total Summary:" + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-success", + children: ["₹", Number(activeLedgerDetail.summary.total_paid || 0).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-dark", + children: ["₹", Number(activeLedgerDetail.summary.total_purchases || 0).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-danger fs-6", + children: ["₹", Number(activeLedgerDetail.summary.outstanding_balance || 0).toFixed(2)] + })] + }) + })] + }) + })] + })] + })] + }), subTab === 'short_items' && /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold mb-0 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle text-warning me-1" + }), " Short Items & Deficiency Reorder Book"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Real-time inventory shortage detection. Select items to generate consolidated Purchase Orders in 1-click." + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-primary btn-sm px-3 shadow-sm fw-bold", + disabled: selectedShortItemIds.length === 0, + onClick: openCreatePoFromShortItems, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-plus me-1" + }), " Create Purchase Order (", selectedShortItemIds.length, " Selected)"] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-primary btn-sm", + onClick: fetchShortItems, + title: "Refresh Short List", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3 bg-light p-2.5 rounded-3 border", + children: [/*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn ${shortFilter === 'all' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setShortFilter('all'), + children: ["All Shortages (", shortItems.length, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${shortFilter === 'out_of_stock' ? 'btn-danger' : 'btn-outline-secondary'}`, + onClick: () => setShortFilter('out_of_stock'), + children: ["Out of Stock (", shortItems.filter(s => s.status === 'OUT_OF_STOCK').length, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${shortFilter === 'low_stock' ? 'btn-warning text-dark' : 'btn-outline-secondary'}`, + onClick: () => setShortFilter('low_stock'), + children: ["Low Stock (", shortItems.filter(s => s.status === 'LOW_STOCK').length, ")"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + style: { + width: 280 + }, + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white border-end-0", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search text-muted" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control border-start-0", + placeholder: "Filter short medicine...", + value: shortSearch, + onChange: e => setShortSearch(e.target.value) + }), shortSearch && /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary", + type: "button", + onClick: () => setShortSearch(''), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + })] + })] + }), (() => { + const filtered = shortItems.filter(it => { + if (shortFilter === 'out_of_stock' && it.status !== 'OUT_OF_STOCK') return false; + if (shortFilter === 'low_stock' && it.status !== 'LOW_STOCK') return false; + if (shortSearch.trim()) { + const q = shortSearch.toLowerCase(); + return it.item_name && it.item_name.toLowerCase().includes(q) || it.category && it.category.toLowerCase().includes(q) || it.last_supplier_name && it.last_supplier_name.toLowerCase().includes(q); + } + return true; + }); + const allSelected = filtered.length > 0 && filtered.every(it => selectedShortItemIds.includes(it.item_id)); + return /*#__PURE__*/_jsx("div", { + className: "table-responsive shadow-sm rounded border", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 40 + }, + className: "text-center", + children: /*#__PURE__*/_jsx("input", { + type: "checkbox", + className: "form-check-input", + checked: allSelected, + onChange: e => { + if (e.target.checked) { + setSelectedShortItemIds(filtered.map(it => it.item_id)); + } else { + setSelectedShortItemIds([]); + } + } + }) + }), /*#__PURE__*/_jsx("th", { + children: "Medicine / Formulation" + }), /*#__PURE__*/_jsx("th", { + children: "Stock Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Current Stock" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Min Reorder" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 110 + }, + children: "Suggested Order" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Estimated PTR" + }), /*#__PURE__*/_jsx("th", { + children: "Last Supplier" + }), /*#__PURE__*/_jsx("th", { + className: "text-end pe-3", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: isLoadingShortItems ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "9", + className: "text-center py-4", + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-2" + }), "Checking stock levels..."] + }) + }) : filtered.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "9", + className: "text-center py-4 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle text-success fs-3 d-block mb-1" + }), "No medicines currently below reorder levels. Inventory is well-stocked!"] + }) + }) : filtered.map(it => { + const isSelected = selectedShortItemIds.includes(it.item_id); + return /*#__PURE__*/_jsxs("tr", { + className: isSelected ? 'table-primary-subtle' : '', + children: [/*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsx("input", { + type: "checkbox", + className: "form-check-input", + checked: isSelected, + onChange: e => { + if (e.target.checked) { + setSelectedShortItemIds([...selectedShortItemIds, it.item_id]); + } else { + setSelectedShortItemIds(selectedShortItemIds.filter(id => id !== it.item_id)); + } + } + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark fs-6", + children: it.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted d-flex gap-2 align-items-center", + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border", + children: it.category || 'Tablet' + }), /*#__PURE__*/_jsx("span", { + children: it.unit_pack || it.units_per_pack + ' Units/Pack' + }), it.drug_schedule && /*#__PURE__*/_jsx("span", { + className: "badge bg-danger-subtle text-danger border", + children: it.drug_schedule + })] + })] + }), /*#__PURE__*/_jsx("td", { + children: it.status === 'OUT_OF_STOCK' ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger-subtle px-2 py-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-x-circle me-1" + }), "Out of Stock"] + }) : /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning-subtle text-warning-emphasis border border-warning-subtle px-2 py-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle me-1" + }), "Low Stock"] + }) + }), /*#__PURE__*/_jsxs("td", { + className: "text-center", + children: [/*#__PURE__*/_jsx("span", { + className: "fw-bold fs-6 text-danger", + children: it.current_qty + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '11px' + }, + children: ["(", it.current_packs, " packs)"] + })] + }), /*#__PURE__*/_jsxs("td", { + className: "text-center text-muted fw-semibold", + children: [it.min_reorder_level, " units"] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm fw-bold text-center", + min: "1", + value: it.suggested_packs, + onChange: e => { + const val = Math.max(1, parseInt(e.target.value) || 1); + setShortItems(shortItems.map(si => si.item_id === it.item_id ? { + ...si, + suggested_packs: val + } : si)); + } + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text py-0 px-1 text-muted", + style: { + fontSize: '11px' + }, + children: "Pks" + })] + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end fw-semibold", + children: it.last_ptr > 0 ? '₹' + Number(it.last_ptr).toFixed(2) : /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "-" + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold text-truncate", + style: { + maxWidth: 180 + }, + title: it.last_supplier_name, + children: it.last_supplier_name + }), it.last_purchase_date && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + style: { + fontSize: '11px' + }, + children: ["Last: ", it.last_purchase_date] + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-end pe-3", + children: /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-primary py-1 px-2 text-nowrap", + onClick: () => { + setSelectedShortItemIds([it.item_id]); + openCreatePoFromShortItems(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart-plus me-1" + }), " Order"] + }) + })] + }, it.item_id); + }) + })] + }) + }); + })()] + }), subTab === 'purchase_orders' && /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold mb-0 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-text text-primary me-1" + }), " Hospital Purchase Orders Directory"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Track order status, print official supplier order formats, and load directly into inward bills." + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-primary btn-sm px-3 shadow-sm fw-semibold", + onClick: () => { + setPoCreateForm({ + supplier_id: suppliers[0]?.supplier_id ? String(suppliers[0].supplier_id) : '', + expected_delivery_date: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], + remarks: '', + items: [{ + item_id: null, + item_name: '', + generic_name: '', + category: 'Tablet', + order_packs: 5, + units_per_pack: 10, + estimated_ptr: 0, + gst_rate: 12 + }] + }); + setShowPoCreateModal(true); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle me-1" + }), " New Purchase Order"] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-primary btn-sm", + onClick: fetchPurchaseOrders, + title: "Refresh PO List", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm mb-3", + children: [/*#__PURE__*/_jsx("button", { + className: `btn ${poStatusFilter === 'all' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => { + setPoStatusFilter('all'); + fetchPurchaseOrders(); + }, + children: "All Orders" + }), /*#__PURE__*/_jsx("button", { + className: `btn ${poStatusFilter === 'ordered' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => { + setPoStatusFilter('ordered'); + fetchPurchaseOrders(); + }, + children: "Ordered / In-Transit" + }), /*#__PURE__*/_jsx("button", { + className: `btn ${poStatusFilter === 'received' ? 'btn-success' : 'btn-outline-secondary'}`, + onClick: () => { + setPoStatusFilter('received'); + fetchPurchaseOrders(); + }, + children: "Received / Inwarded" + }), /*#__PURE__*/_jsx("button", { + className: `btn ${poStatusFilter === 'cancelled' ? 'btn-danger' : 'btn-outline-secondary'}`, + onClick: () => { + setPoStatusFilter('cancelled'); + fetchPurchaseOrders(); + }, + children: "Cancelled" + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive shadow-sm rounded border", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover align-middle mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "PO Number" + }), /*#__PURE__*/_jsx("th", { + children: "PO Date" + }), /*#__PURE__*/_jsx("th", { + children: "Expected Delivery" + }), /*#__PURE__*/_jsx("th", { + children: "Supplier / Distributor" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Items" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Est. Total Amount" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-end pe-3", + children: "Actions" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: isLoadingPOs ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "8", + className: "text-center py-4", + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-2" + }), "Loading purchase orders..."] + }) + }) : purchaseOrders.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No purchase orders found. Click \"New Purchase Order\" or generate from Short Items." + }) + }) : purchaseOrders.map(po => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-bold text-primary", + children: po.po_number + }), /*#__PURE__*/_jsx("td", { + children: po.po_date + }), /*#__PURE__*/_jsx("td", { + children: po.expected_delivery_date || /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "-" + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold text-dark", + children: po.supplier_name + }), po.phone && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-1" + }), po.phone] + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-center fw-bold", + children: po.total_items + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", Number(po.total_estimated_amount || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsxs("td", { + className: "text-center", + children: [po.status === 'ordered' && /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle px-2 py-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock me-1" + }), "Ordered"] + }), po.status === 'received' && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success-subtle px-2 py-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-circle me-1" + }), "Received"] + }), po.status === 'cancelled' && /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary border px-2 py-1", + children: "Cancelled" + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-end pe-3", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-primary", + onClick: () => handleViewPo(po.po_id), + title: "View & Print PO", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print"] + }), po.status === 'ordered' && /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-success", + onClick: () => loadPoIntoInwardBill(po.po_id), + title: "Load this PO into Inward Purchase Bill", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-down me-1" + }), " Inward"] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-danger", + onClick: () => handleCancelPo(po.po_id), + title: "Cancel this PO", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + })] + })] + }) + })] + }, po.po_id)) + })] + }) + })] + }), showSupplierModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-primary text-white rounded p-1.5 d-flex align-items-center justify-content-center", + style: { + width: 32, + height: 32 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-truck fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: supplierForm.supplier_id ? 'Edit Supplier / Distributor Details' : 'Add New Drug Distributor & Supplier' + }), /*#__PURE__*/_jsx("small", { + className: "text-light opacity-75", + children: "Statutory Drug Licenses, GSTIN, contact & credit terms" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowSupplierModal(false) + })] + }), /*#__PURE__*/_jsxs("form", { + onSubmit: handleSaveSupplier, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-body p-3 bg-light", + children: [/*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm p-3 mb-3 bg-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-primary mb-2", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-building me-1" + }), " Basic Distributor Information"] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-8", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Distributor / Agency Name ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Apex Healthcare Distributors Pvt Ltd", + value: supplierForm.supplier_name, + onChange: e => setSupplierForm({ + ...supplierForm, + supplier_name: e.target.value + }), + required: true, + autoFocus: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Contact Person" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Ramesh Gupta", + value: supplierForm.contact_person, + onChange: e => setSupplierForm({ + ...supplierForm, + contact_person: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Phone / Mobile No." + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "+91 9811002233", + value: supplierForm.phone, + onChange: e => setSupplierForm({ + ...supplierForm, + phone: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Email Address" + }), /*#__PURE__*/_jsx("input", { + type: "email", + className: "form-control form-control-sm", + placeholder: "sales@distributor.com", + value: supplierForm.email, + onChange: e => setSupplierForm({ + ...supplierForm, + email: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Credit Terms" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm", + min: "0", + placeholder: "30", + value: supplierForm.credit_days, + onChange: e => setSupplierForm({ + ...supplierForm, + credit_days: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: "Days" + })] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm p-3 mb-3 bg-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-primary mb-2", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " Indian Statutory Drug Licenses & GSTIN"] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Drug License Form 20-B (Allopathic)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. DL-20B-DEL-98441", + value: supplierForm.dl_no_20b, + onChange: e => setSupplierForm({ + ...supplierForm, + dl_no_20b: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Drug License Form 21-B (Schedule C & C1)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. DL-21B-DEL-98442", + value: supplierForm.dl_no_21b, + onChange: e => setSupplierForm({ + ...supplierForm, + dl_no_21b: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "GSTIN (15-Digit)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm text-uppercase", + maxLength: "15", + placeholder: "07AACCA1234F1Z9", + value: supplierForm.gstin, + onChange: e => setSupplierForm({ + ...supplierForm, + gstin: e.target.value.toUpperCase() + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "PAN No. (10-Digit)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm text-uppercase", + maxLength: "10", + placeholder: "AACCA1234F", + value: supplierForm.pan_no, + onChange: e => setSupplierForm({ + ...supplierForm, + pan_no: e.target.value.toUpperCase() + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "State Code (GST)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "07 (Delhi)", + value: supplierForm.state_code, + onChange: e => setSupplierForm({ + ...supplierForm, + state_code: e.target.value + }) + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm p-3 bg-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-primary mb-2", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-geo-alt me-1" + }), " Address & Banking Details"] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Full Postal Address" + }), /*#__PURE__*/_jsx("textarea", { + className: "form-control form-control-sm", + rows: "2", + placeholder: "Shop / Office No, Market, City, Pincode", + value: supplierForm.address, + onChange: e => setSupplierForm({ + ...supplierForm, + address: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Bank Account & Settlement Details" + }), /*#__PURE__*/_jsx("textarea", { + className: "form-control form-control-sm", + rows: "2", + placeholder: "Bank Name, A/c Number, IFSC Code, UPI ID", + value: supplierForm.bank_details, + onChange: e => setSupplierForm({ + ...supplierForm, + bank_details: e.target.value + }) + })] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-white d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm", + onClick: () => setShowSupplierModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-primary btn-sm px-4", + disabled: isSavingSupplier, + children: isSavingSupplier ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-1", + role: "status" + }), "Saving..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-circle me-1" + }), supplierForm.supplier_id ? 'Update Supplier' : 'Save Supplier'] + }) + })] + })] + })] + }) + }) + }), showMasterModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-success text-white rounded p-1.5 d-flex align-items-center justify-content-center", + style: { + width: 32, + height: 32 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-capsule fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: "Add New Medicine to Pharmacy Master" + }), /*#__PURE__*/_jsxs("small", { + className: "text-light opacity-75", + children: ["Saved to shared master ", /*#__PURE__*/_jsx("code", { + children: "med_product_master" + }), " (shared between MedicalStore & HMSPharmacy)"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowMasterModal(false) + })] + }), /*#__PURE__*/_jsxs("form", { + onSubmit: handleSaveMasterMedicine, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-body p-3 bg-light", + children: [/*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm p-3 mb-3 bg-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-primary mb-2", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-prescription2 me-1" + }), " Medicine Name & Formulation"] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-7", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Brand / Medicine Name ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm fw-semibold", + placeholder: "e.g. Augmentin 625 Duo Tablet", + value: masterForm.item_name, + onChange: e => setMasterForm({ + ...masterForm, + item_name: e.target.value + }), + required: true, + autoFocus: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-5", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Formulation / Category" + }), /*#__PURE__*/_jsx("input", { + type: "text", + list: "ms-formulation-list", + className: "form-control form-control-sm", + placeholder: "e.g. Tablet, Capsule, Syrup...", + value: masterForm.formulation, + onChange: e => setMasterForm({ + ...masterForm, + formulation: e.target.value + }) + }), /*#__PURE__*/_jsx("datalist", { + id: "ms-formulation-list", + children: (supportData.formulations || []).map((f, idx) => /*#__PURE__*/_jsx("option", { + value: f + }, idx)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Generic Molecule Composition" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Amoxycillin (500mg) + Clavulanic Acid (125mg)", + value: masterForm.generic_name, + onChange: e => setMasterForm({ + ...masterForm, + generic_name: e.target.value + }) + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm p-3 bg-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-primary mb-2", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-seam me-1" + }), " Packing, Tax & Regulatory Specifications"] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Units per Pack (Strip/Bottle) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "number", + min: "1", + className: "form-control form-control-sm fw-bold", + placeholder: "10", + value: masterForm.units_per_pack, + onChange: e => setMasterForm({ + ...masterForm, + units_per_pack: e.target.value, + packing: e.target.value + }), + required: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "GST Rate (%)" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm fw-bold", + value: masterForm.gst_rate, + onChange: e => setMasterForm({ + ...masterForm, + gst_rate: Number(e.target.value) + }), + children: [/*#__PURE__*/_jsx("option", { + value: "0", + children: "0% (Nil / Exempt)" + }), /*#__PURE__*/_jsx("option", { + value: "5", + children: "5% (Common / Basic Services)" + }), /*#__PURE__*/_jsx("option", { + value: "18", + children: "18% (Standard - Most Products)" + }), /*#__PURE__*/_jsx("option", { + value: "40", + children: "40% (Demerit / Sin Tax)" + }), /*#__PURE__*/_jsx("option", { + value: "12", + children: "12% (Legacy Medicine Slab)" + }), /*#__PURE__*/_jsx("option", { + value: "28", + children: "28% (Legacy High Slab)" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "HSN Code" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "3004", + value: masterForm.hsn_code, + onChange: e => setMasterForm({ + ...masterForm, + hsn_code: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Drug Schedule" + }), /*#__PURE__*/_jsx("select", { + className: "form-select form-select-sm", + value: masterForm.drug_schedule, + onChange: e => setMasterForm({ + ...masterForm, + drug_schedule: e.target.value + }), + children: (supportData.schedules || ['OTC', 'Schedule H', 'Schedule H1', 'Schedule X', 'Narcotic']).map((sc, idx) => /*#__PURE__*/_jsx("option", { + value: sc, + children: sc + }, idx)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-8", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Manufacturer / Pharma Company" + }), /*#__PURE__*/_jsx("input", { + type: "text", + list: "ms-company-list", + className: "form-control form-control-sm", + placeholder: "e.g. Cipla Ltd, Sun Pharma, Alkem...", + value: masterForm.company_name, + onChange: e => setMasterForm({ + ...masterForm, + company_name: e.target.value + }) + }), /*#__PURE__*/_jsx("datalist", { + id: "ms-company-list", + children: (supportData.companies || []).map((c, idx) => /*#__PURE__*/_jsx("option", { + value: c + }, idx)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Min Reorder Level" + }), /*#__PURE__*/_jsx("input", { + type: "number", + min: "1", + className: "form-control form-control-sm", + placeholder: "10", + value: masterForm.min_reorder_level, + onChange: e => setMasterForm({ + ...masterForm, + min_reorder_level: e.target.value + }) + })] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-white d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm", + onClick: () => setShowMasterModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-success btn-sm fw-bold px-4", + disabled: isSavingMaster, + children: isSavingMaster ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-1", + role: "status" + }), "Saving to Master..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle me-1" + }), "Save to Master & Select into Bill"] + }) + })] + })] + })] + }) + }) + }), showPaymentModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-md modal-dialog-centered", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-success text-white rounded p-1.5 d-flex align-items-center justify-content-center", + style: { + width: 32, + height: 32 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-cash-coin fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: "Record Supplier Payment Voucher" + }), /*#__PURE__*/_jsx("small", { + className: "text-light opacity-75", + children: "Outflow accounting against invoice or on-account" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowPaymentModal(false) + })] + }), /*#__PURE__*/_jsxs("form", { + onSubmit: handleRecordPayment, + children: [/*#__PURE__*/_jsx("div", { + className: "modal-body p-3 bg-light", + children: /*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 mb-3 bg-white", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Supplier / Distributor ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm fw-semibold", + value: paymentForm.supplier_id, + onChange: e => setPaymentForm({ + ...paymentForm, + supplier_id: e.target.value + }), + required: true, + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "-- Choose Supplier --" + }), suppliers.map(s => /*#__PURE__*/_jsxs("option", { + value: s.supplier_id, + children: [s.supplier_name, " (GST: ", s.gstin || 'N/A', ")"] + }, s.supplier_id))] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Payment Amount (₹) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + min: "0.01", + className: "form-control form-control-sm fw-bold text-success fs-6", + placeholder: "0.00", + value: paymentForm.amount, + onChange: e => setPaymentForm({ + ...paymentForm, + amount: e.target.value + }), + required: true, + autoFocus: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Payment Mode" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: paymentForm.payment_mode, + onChange: e => setPaymentForm({ + ...paymentForm, + payment_mode: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "Bank", + children: "Bank Transfer (NEFT/RTGS)" + }), /*#__PURE__*/_jsx("option", { + value: "UPI", + children: "UPI / QR Code" + }), /*#__PURE__*/_jsx("option", { + value: "Cash", + children: "Cash in Hand" + }), /*#__PURE__*/_jsx("option", { + value: "Cheque", + children: "Bank Cheque" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Payment Date" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: paymentForm.payment_date, + onChange: e => setPaymentForm({ + ...paymentForm, + payment_date: e.target.value + }), + required: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "UTR / Cheque / Ref No" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. UTR-9988112", + value: paymentForm.reference_no, + onChange: e => setPaymentForm({ + ...paymentForm, + reference_no: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Bank Name / Account Details" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. HDFC Bank - Main Current A/c", + value: paymentForm.bank_name, + onChange: e => setPaymentForm({ + ...paymentForm, + bank_name: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Remarks / Settlement Note" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Cleared bill #APX-9941", + value: paymentForm.remarks, + onChange: e => setPaymentForm({ + ...paymentForm, + remarks: e.target.value + }) + })] + })] + }) + }) + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-white d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm", + onClick: () => setShowPaymentModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-success btn-sm fw-bold px-4 shadow-sm", + disabled: isRecordingPayment, + children: isRecordingPayment ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-1" + }), "Recording Voucher..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-circle me-1" + }), "Record Payment Voucher"] + }) + })] + })] + })] + }) + }) + }), showPoCreateModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-primary text-white rounded p-1.5 d-flex align-items-center justify-content-center", + style: { + width: 32, + height: 32 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-cart-check fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: "Generate New Purchase Order (PO)" + }), /*#__PURE__*/_jsx("small", { + className: "text-light opacity-75", + children: "Order requisition for pharmaceutical distributor" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowPoCreateModal(false) + })] + }), /*#__PURE__*/_jsxs("form", { + onSubmit: handleSavePurchaseOrder, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-body p-3 bg-light", + children: [/*#__PURE__*/_jsx("div", { + className: "card border-0 shadow-sm p-3 mb-3 bg-white", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-5", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Target Supplier / Agency ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm fw-semibold", + value: poCreateForm.supplier_id, + onChange: e => setPoCreateForm({ + ...poCreateForm, + supplier_id: e.target.value + }), + required: true, + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "-- Choose Supplier --" + }), suppliers.map(s => /*#__PURE__*/_jsxs("option", { + value: s.supplier_id, + children: [s.supplier_name, " (GST: ", s.gstin || 'N/A', ")"] + }, s.supplier_id))] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Expected Delivery Date" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: poCreateForm.expected_delivery_date, + onChange: e => setPoCreateForm({ + ...poCreateForm, + expected_delivery_date: e.target.value + }), + required: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Remarks / Order Instructions" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Urgent stock replenishment", + value: poCreateForm.remarks, + onChange: e => setPoCreateForm({ + ...poCreateForm, + remarks: e.target.value + }) + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 shadow-sm p-3 bg-white", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold text-primary mb-0", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-seam me-1" + }), " Ordered Items (", poCreateForm.items.length, ")"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-outline-primary btn-sm py-0.5 px-2", + onClick: () => { + setPoCreateForm({ + ...poCreateForm, + items: [...poCreateForm.items, { + item_id: null, + item_name: '', + generic_name: '', + category: 'Tablet', + order_packs: 1, + units_per_pack: 10, + estimated_ptr: 0, + gst_rate: 12 + }] + }); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus me-1" + }), " Add Another Medicine"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-bordered align-middle mb-0", + style: { + fontSize: '12.5px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + minWidth: 240 + }, + children: "Medicine Name" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 100 + }, + children: "Category" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 90 + }, + children: "Packs" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 90 + }, + children: "Units/Pack" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 100 + }, + children: "Est. PTR (₹)" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 85 + }, + children: "GST%" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 120 + }, + className: "text-end", + children: "Est. Total (₹)" + }), /*#__PURE__*/_jsx("th", { + style: { + width: 40 + } + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: poCreateForm.items.map((it, idx) => { + const lineTotal = Number(it.order_packs || 0) * Number(it.estimated_ptr || 0) * (1 + Number(it.gst_rate || 0) / 100); + return /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm fw-semibold", + placeholder: "Medicine name...", + value: it.item_name, + onChange: e => { + const items = [...poCreateForm.items]; + items[idx].item_name = e.target.value; + setPoCreateForm({ + ...poCreateForm, + items + }); + }, + required: true + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: it.category, + onChange: e => { + const items = [...poCreateForm.items]; + items[idx].category = e.target.value; + setPoCreateForm({ + ...poCreateForm, + items + }); + } + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("input", { + type: "number", + min: "1", + className: "form-control form-control-sm text-center fw-bold", + value: it.order_packs, + onChange: e => { + const items = [...poCreateForm.items]; + items[idx].order_packs = Math.max(1, parseInt(e.target.value) || 1); + setPoCreateForm({ + ...poCreateForm, + items + }); + }, + required: true + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("input", { + type: "number", + min: "1", + className: "form-control form-control-sm text-center", + value: it.units_per_pack, + onChange: e => { + const items = [...poCreateForm.items]; + items[idx].units_per_pack = Math.max(1, parseInt(e.target.value) || 1); + setPoCreateForm({ + ...poCreateForm, + items + }); + } + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + min: "0", + className: "form-control form-control-sm text-end", + value: it.estimated_ptr, + onChange: e => { + const items = [...poCreateForm.items]; + items[idx].estimated_ptr = parseFloat(e.target.value) || 0; + setPoCreateForm({ + ...poCreateForm, + items + }); + } + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: it.gst_rate, + onChange: e => { + const items = [...poCreateForm.items]; + items[idx].gst_rate = parseFloat(e.target.value) || 0; + setPoCreateForm({ + ...poCreateForm, + items + }); + }, + children: [/*#__PURE__*/_jsx("option", { + value: "0", + children: "0% (Exempt)" + }), /*#__PURE__*/_jsx("option", { + value: "5", + children: "5%" + }), /*#__PURE__*/_jsx("option", { + value: "18", + children: "18%" + }), /*#__PURE__*/_jsx("option", { + value: "40", + children: "40%" + }), /*#__PURE__*/_jsx("option", { + value: "12", + children: "12% (Legacy)" + }), /*#__PURE__*/_jsx("option", { + value: "28", + children: "28% (Legacy)" + })] + }) + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", lineTotal.toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: poCreateForm.items.length > 1 && /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-danger py-0 px-1", + onClick: () => { + setPoCreateForm({ + ...poCreateForm, + items: poCreateForm.items.filter((_, i) => i !== idx) + }); + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + }) + })] + }, idx); + }) + }), /*#__PURE__*/_jsx("tfoot", { + className: "table-light fw-bold", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + colSpan: "6", + className: "text-end", + children: "Estimated Total Amount:" + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-primary fs-6", + children: ["₹", poCreateForm.items.reduce((sum, it) => sum + Number(it.order_packs || 0) * Number(it.estimated_ptr || 0) * (1 + Number(it.gst_rate || 0) / 100), 0).toFixed(2)] + }), /*#__PURE__*/_jsx("td", {})] + }) + })] + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-white d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm", + onClick: () => setShowPoCreateModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-primary btn-sm fw-bold px-4 shadow-sm", + disabled: isSavingPO, + children: isSavingPO ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-1" + }), "Generating PO..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-circle me-1" + }), "Generate Purchase Order"] + }) + })] + })] + })] + }) + }) + }), showPoViewModal && activeViewPo && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-primary text-white rounded p-1.5 d-flex align-items-center justify-content-center", + style: { + width: 32, + height: 32 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-printer fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title mb-0 fw-bold", + children: ["Purchase Order Document: ", activeViewPo.purchase_order.po_number] + }), /*#__PURE__*/_jsxs("small", { + className: "text-light opacity-75", + children: ["Status: ", /*#__PURE__*/_jsx("span", { + className: "text-uppercase fw-bold text-info", + children: activeViewPo.purchase_order.status + })] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowPoViewModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-4 bg-white", + id: "printable-po-document", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start border-bottom pb-3 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h4", { + className: "fw-bold text-primary mb-1", + children: store.store_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted small", + children: [store.building_name, " | ", store.room_no] + }), /*#__PURE__*/_jsx("div", { + className: "text-muted small", + children: "Hospital Pharmacy & Medical Supplies Dept." + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsx("h5", { + className: "fw-bold mb-0 text-dark", + children: "PURCHASE ORDER" + }), /*#__PURE__*/_jsx("div", { + className: "badge bg-primary fs-6 mt-1", + children: activeViewPo.purchase_order.po_number + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted mt-1", + children: ["Date: ", /*#__PURE__*/_jsx("strong", { + children: activeViewPo.purchase_order.po_date + })] + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + children: ["Delivery: ", /*#__PURE__*/_jsx("strong", { + children: activeViewPo.purchase_order.expected_delivery_date || 'Prompt' + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2.5 bg-light rounded border", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted text-uppercase fw-bold", + style: { + fontSize: '10px' + }, + children: "Vendor / Supplier:" + }), /*#__PURE__*/_jsx("h6", { + className: "fw-bold mb-1 text-dark", + children: activeViewPo.purchase_order.supplier_name + }), activeViewPo.purchase_order.address && /*#__PURE__*/_jsx("div", { + className: "small text-muted", + children: activeViewPo.purchase_order.address + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + children: ["GSTIN: ", /*#__PURE__*/_jsx("strong", { + children: activeViewPo.purchase_order.gstin || 'N/A' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + children: ["Phone: ", activeViewPo.purchase_order.phone || 'N/A'] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2.5 bg-light rounded border", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted text-uppercase fw-bold", + style: { + fontSize: '10px' + }, + children: "Ship To / Delivery Destination:" + }), /*#__PURE__*/_jsx("h6", { + className: "fw-bold mb-1 text-dark", + children: store.store_name + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + children: [store.building_name, ", ", store.floor_no] + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + children: ["Remarks: ", /*#__PURE__*/_jsx("em", { + children: activeViewPo.purchase_order.remarks || 'Supply per hospital contract terms' + })] + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive mb-3", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-bordered table-sm align-middle mb-0", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 35 + }, + children: "#" + }), /*#__PURE__*/_jsx("th", { + children: "Item Name & Description" + }), /*#__PURE__*/_jsx("th", { + children: "Category" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 85 + }, + children: "Ordered Packs" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 85 + }, + children: "Units/Pack" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 95 + }, + children: "Est. PTR" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + style: { + width: 65 + }, + children: "GST%" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + style: { + width: 110 + }, + children: "Est. Amount" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: activeViewPo.items?.map((it, idx) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "text-muted text-center", + children: idx + 1 + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: it.item_name + }), it.generic_name && /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: it.generic_name + })] + }), /*#__PURE__*/_jsx("td", { + children: it.category || 'Tablet' + }), /*#__PURE__*/_jsx("td", { + className: "text-center fw-bold", + children: it.order_packs + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: it.units_per_pack + }), /*#__PURE__*/_jsxs("td", { + className: "text-end", + children: ["₹", Number(it.estimated_ptr).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-center", + children: [it.gst_rate, "%"] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", Number(it.estimated_amount).toFixed(2)] + })] + }, idx)) + }), /*#__PURE__*/_jsx("tfoot", { + className: "table-light fw-bold", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + colSpan: "7", + className: "text-end", + children: "Total Estimated Value:" + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-primary fs-6", + children: ["₹", Number(activeViewPo.purchase_order.total_estimated_amount).toFixed(2)] + })] + }) + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-end pt-4 mt-4 border-top", + children: [/*#__PURE__*/_jsxs("div", { + className: "text-center", + style: { + width: 180 + }, + children: [/*#__PURE__*/_jsx("div", { + className: "border-bottom pb-4 mb-1" + }), /*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "Prepared By / Pharmacist" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-center", + style: { + width: 180 + }, + children: [/*#__PURE__*/_jsx("div", { + className: "border-bottom pb-4 mb-1" + }), /*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "Authorized Signatory" + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-light d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary btn-sm", + onClick: () => setShowPoViewModal(false), + children: "Close" + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [activeViewPo.purchase_order.status === 'ordered' && /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-success btn-sm fw-bold px-3 shadow-sm", + onClick: () => loadPoIntoInwardBill(activeViewPo.purchase_order.po_id), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-box-arrow-in-down me-1" + }), " Inward into Purchase Bill"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-primary btn-sm fw-bold px-3 shadow-sm", + onClick: () => window.print(), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print PO"] + })] + })] + })] + }) + }) + }), showPurchaseHistoryModal && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.75)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3 d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "bg-primary text-white rounded p-1.5 d-flex align-items-center justify-content-center", + style: { + width: 32, + height: 32 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history fs-5" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title mb-0 fw-bold", + children: "Inward Purchase Bills History & Edit" + }), /*#__PURE__*/_jsx("small", { + className: "text-light opacity-75", + children: "Browse past invoices and click Edit to modify lines, rates, or batches" + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowPurchaseHistoryModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3 bg-light", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center gap-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + style: { + maxWidth: 350 + }, + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search text-muted" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "Search by Bill No or Supplier Name...", + value: purchaseHistorySearch, + onChange: e => setPurchaseHistorySearch(e.target.value) + }), purchaseHistorySearch && /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary", + onClick: () => setPurchaseHistorySearch(''), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-primary btn-sm", + onClick: fetchRecentPurchases, + title: "Refresh Invoices", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise me-1" + }), " Refresh"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive bg-white rounded border shadow-sm", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-hover align-middle mb-0", + style: { + fontSize: '13px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: 110 + }, + children: "Date" + }), /*#__PURE__*/_jsx("th", { + children: "Bill / Invoice No" + }), /*#__PURE__*/_jsx("th", { + children: "Supplier / Distributor" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Items" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Net Bill Amount" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Paid Amount" + }), /*#__PURE__*/_jsx("th", { + className: "text-center", + children: "Payment Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-end pe-3", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: isLoadingPurchases ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "8", + className: "text-center py-4", + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-2" + }), "Loading invoices..."] + }) + }) : recentPurchases.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No inward purchase bills recorded yet." + }) + }) : recentPurchases.filter(p => { + if (!purchaseHistorySearch) return true; + const q = purchaseHistorySearch.toLowerCase(); + return (p.supplier_invoice_no || '').toLowerCase().includes(q) || (p.supplier_name || '').toLowerCase().includes(q); + }).map(p => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: p.invoice_date + }), /*#__PURE__*/_jsx("td", { + className: "fw-bold text-primary", + children: p.supplier_invoice_no + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-semibold text-dark", + children: p.supplier_name || 'Unknown Supplier' + }), p.gstin && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: ["GST: ", p.gstin] + })] + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border px-2 py-1", + children: [p.items_count || 1, " lines"] + }) + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold text-dark", + children: ["₹", Number(p.net_amount || 0).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end text-success", + children: ["₹", Number(p.paid_amount || 0).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + className: "text-center", + children: /*#__PURE__*/_jsx("span", { + className: `badge ${p.payment_status === 'paid' ? 'bg-success' : p.payment_status === 'partially_paid' ? 'bg-warning text-dark' : 'bg-danger'} px-2 py-1`, + children: p.payment_status === 'paid' ? 'Paid' : p.payment_status === 'partially_paid' ? 'Partially Paid' : 'Unpaid' + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end pe-3", + children: /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-primary py-1 px-2.5 shadow-sm fw-semibold", + onClick: () => loadPurchaseForEdit(p.purchase_id), + title: "Load this bill into Inward form to edit items and rates", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square me-1" + }), " Edit Invoice"] + }) + })] + }, p.purchase_id)) + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "modal-footer py-2 bg-light", + children: /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-secondary btn-sm", + onClick: () => setShowPurchaseHistoryModal(false), + children: "Close" + }) + })] + }) + }) + })] + }); +} + +// ========================================================================= +// 4. INTER-STORE INDENTS & TRANSFERS +// ========================================================================= +function TransferView({ + store, + stores, + notify +}) { + if (!store) return null; + const [toStoreId, setToStoreId] = useState(''); + const [remarks, setRemarks] = useState(''); + const [transferItems, setTransferItems] = useState([{ + item_name: '', + qty: 10 + }]); + const addTransferRow = () => { + setTransferItems([...transferItems, { + item_name: '', + qty: 10 + }]); + }; + const submitIndent = async () => { + if (!toStoreId) { + notify('Please select destination store counter.', 'error'); + return; + } + try { + const res = await fetch(API_BASE + 'transfer/request', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + from_store_id: store.store_id, + to_store_id: Number(toStoreId), + remarks: remarks, + items: transferItems.map(it => ({ + item_id: 1, + qty: Number(it.qty) + })) + }) + }); + const data = await res.json(); + if (data.status) { + notify(`Store Indent ${data.transfer_no} submitted to Central Pharmacy!`, 'success'); + setRemarks(''); + } else { + notify(data.message || 'Failed to submit indent.', 'error'); + } + } catch (e) { + notify('Indent error: ' + e.message, 'error'); + } + }; + return /*#__PURE__*/_jsxs("div", { + className: "counter-card", + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bold mb-3", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left-right text-primary me-1" + }), " Multi-Building Store Requisition (Indent)"] + }), /*#__PURE__*/_jsx("p", { + className: "text-muted small", + children: "Building counters can requisition medicines from the Main Hospital Central Store. Once dispatched and physically verified, stock transfers automatically." + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold", + children: "Source Store (From)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: store.store_name, + disabled: true + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold", + children: "Target Counter / Building (To)" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: toStoreId, + onChange: e => setToStoreId(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "-- Select Destination Store --" + }), stores.filter(s => s.store_id !== store.store_id).map(s => /*#__PURE__*/_jsxs("option", { + value: s.store_id, + children: [s.store_name, " (", s.store_slug, ")"] + }, s.store_id))] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold", + children: "Requested Medicines" + }), transferItems.map((ti, i) => /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsx("div", { + className: "col-8", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "Medicine Name", + value: ti.item_name, + onChange: e => { + const updated = [...transferItems]; + updated[i].item_name = e.target.value; + setTransferItems(updated); + } + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm", + placeholder: "Quantity Required", + min: "1", + value: ti.qty, + onChange: e => { + const updated = [...transferItems]; + updated[i].qty = e.target.value; + setTransferItems(updated); + } + }) + })] + }, i)), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-primary mt-1", + onClick: addTransferRow, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle me-1" + }), " Add Another Medicine"] + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-primary-custom", + onClick: submitIndent, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-send me-1" + }), " Submit Store Indent Requisition"] + })] + }); +} + +// ========================================================================= +// 5. ACCOUNTING, LEDGERS, DAYBOOK & GST REPORTS +// ========================================================================= +function LedgersView({ + store, + notify +}) { + if (!store) return null; + const [accTab, setAccTab] = useState('daybook'); // 'daybook', 'bank_audit', 'gst', 'schedule_h1', 'credit_accounts' + + // Helper: CSV Download + const downloadCsv = (filename, rows) => { + const csvContent = "data:text/csv;charset=utf-8," + rows.map(e => e.map(cell => `"${String(cell ?? '').replace(/"/g, '""')}"`).join(",")).join("\n"); + const encodedUri = encodeURI(csvContent); + const link = document.createElement("a"); + link.setAttribute("href", encodedUri); + link.setAttribute("download", filename); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + + // Helper: Open Print Window + const openPrintReport = (title, bodyHtml) => { + const win = window.open('', '_blank', 'width=950,height=750'); + if (!win) { + notify('Please allow popups to print report', 'warning'); + return; + } + const printDoc = win.document; + printDoc.open(); + const headerHtml = '
' + '
' + title + ' — Ready to print
' + '
' + '
' + ''; + printDoc.write('<' + 'head>' + title + '' + '' + '' + '' + headerHtml + bodyHtml + ''); + printDoc.close(); + }; + + // 1. Daybook State + const todayStr = new Date().toISOString().split('T')[0]; + const [daybookFromDate, setDaybookFromDate] = useState(todayStr); + const [daybookToDate, setDaybookToDate] = useState(todayStr); + const [daybookData, setDaybookData] = useState(null); + const [loadingDaybook, setLoadingDaybook] = useState(false); + + // 2. Bank Audit State + const [bankAuditData, setBankAuditData] = useState(null); + const [auditFilterStatus, setAuditFilterStatus] = useState('all'); + const [auditSearch, setAuditSearch] = useState(''); + const [reconcilingSale, setReconcilingSale] = useState(null); + const [auditNotes, setAuditNotes] = useState(''); + const [auditorName, setAuditorName] = useState('Accountant'); + const [isSubmittingAudit, setIsSubmittingAudit] = useState(false); + + // 3. GST State + const currentMonthStr = todayStr.substring(0, 7); // YYYY-MM + const [gstMonth, setGstMonth] = useState(currentMonthStr); + const [gstData, setGstData] = useState(null); + const [loadingGst, setLoadingGst] = useState(false); + + // 4. Schedule H1 State + const [h1FromDate, setH1FromDate] = useState(todayStr); + const [h1ToDate, setH1ToDate] = useState(todayStr); + const [h1Search, setH1Search] = useState(''); + const [h1Records, setH1Records] = useState([]); + const [loadingH1, setLoadingH1] = useState(false); + + // 5. Staff & Customer Credit Accounts State + const [creditAccounts, setCreditAccounts] = useState([]); + const [loadingCredit, setLoadingCredit] = useState(false); + const [creditSearch, setCreditSearch] = useState(''); + const [showAddAccountModal, setShowAddAccountModal] = useState(false); + const [accFormType, setAccFormType] = useState('staff'); + const [accFormName, setAccFormName] = useState(''); + const [accFormPhone, setAccFormPhone] = useState(''); + const [accFormStaffId, setAccFormStaffId] = useState(''); + const [accFormDept, setAccFormDept] = useState(''); + const [accFormLimit, setAccFormLimit] = useState('5000'); + const [accFormRemarks, setAccFormRemarks] = useState(''); + const [isSavingAccount, setIsSavingAccount] = useState(false); + + // Credit Ledger Statement & Payment Settle Modal + const [selectedCreditAcc, setSelectedCreditAcc] = useState(null); + const [creditLedgerData, setCreditLedgerData] = useState(null); + const [loadingLedger, setLoadingLedger] = useState(false); + const [showPaymentModal, setShowPaymentModal] = useState(false); + const [payAmount, setPayAmount] = useState(''); + const [payMode, setPayMode] = useState('Cash'); + const [payRef, setPayRef] = useState(''); + const [payRemarks, setPayRemarks] = useState(''); + const [isRecordingPayment, setIsRecordingPayment] = useState(false); + useEffect(() => { + if (!store?.store_id) return; + if (accTab === 'daybook') loadDaybook(daybookFromDate, daybookToDate); + if (accTab === 'bank_audit') loadBankAudit(auditFilterStatus, auditSearch); + if (accTab === 'gst') loadGst(gstMonth); + if (accTab === 'schedule_h1') loadScheduleH1(h1FromDate, h1ToDate, h1Search); + if (accTab === 'credit_accounts') loadCreditAccounts(); + }, [accTab, store?.store_id]); + + // DAYBOOK FUNCTIONS + const loadDaybook = async (from = daybookFromDate, to = daybookToDate) => { + setLoadingDaybook(true); + try { + const res = await fetch(`${API_BASE}accounting/daybook?store_id=${store.store_id}&from_date=${from}&to_date=${to}`); + const data = await res.json(); + if (data.status) setDaybookData(data); + } catch (e) { + console.error(e); + notify('Error loading daybook: ' + e.message, 'error'); + } finally { + setLoadingDaybook(false); + } + }; + const handleDaybookFilterPreset = preset => { + const today = new Date(); + let from = todayStr; + let to = todayStr; + if (preset === 'today') { + from = todayStr; + to = todayStr; + } else if (preset === 'yesterday') { + const y = new Date(today); + y.setDate(today.getDate() - 1); + from = y.toISOString().split('T')[0]; + to = from; + } else if (preset === 'last7') { + const w = new Date(today); + w.setDate(today.getDate() - 6); + from = w.toISOString().split('T')[0]; + to = todayStr; + } else if (preset === 'month') { + from = `${todayStr.substring(0, 7)}-01`; + to = todayStr; + } + setDaybookFromDate(from); + setDaybookToDate(to); + loadDaybook(from, to); + }; + const exportDaybookCsv = () => { + if (!daybookData || !daybookData.transactions?.length) { + notify('No transactions to export for selected dates.', 'warning'); + return; + } + const headers = ['Invoice No', 'Sale Date', 'Patient Name', 'UHID', 'Doctor Name', 'Payment Mode', 'Subtotal (Rs)', 'Discount (Rs)', 'CGST (Rs)', 'SGST (Rs)', 'Net Amount (Rs)']; + const rows = daybookData.transactions.map(t => [t.invoice_no, t.sale_date, t.patient_name, t.uhid || '', t.doctor_name, t.payment_mode, t.subtotal, t.discount_amount, t.cgst_amount, t.sgst_amount, t.net_amount]); + downloadCsv(`Daybook_${daybookFromDate}_to_${daybookToDate}.csv`, [headers, ...rows]); + notify('Daybook CSV exported successfully.', 'success'); + }; + const printDaybook = () => { + if (!daybookData || !daybookData.transactions?.length) { + notify('No transactions to print.', 'warning'); + return; + } + const s = daybookData.summary; + const html = ` +
+
Total Sales: ₹${Number(s.total_sales || 0).toLocaleString('en-IN')} (${s.total_invoices} bills)
+
Cash in Drawer: ₹${Number(s.cash_in_drawer || 0).toLocaleString('en-IN')}
+
UPI / QR: ₹${Number(s.upi_collection || 0).toLocaleString('en-IN')}
+
IPD / Staff Credit: ₹${Number(s.ipd_credit || 0).toLocaleString('en-IN')}
+
+

Period: ${daybookFromDate} to ${daybookToDate}

+ + + + + + + + + + + + + + + ${daybookData.transactions.map(t => ` + + + + + + + + + + + `).join('')} + +
Invoice NoDate & TimePatient Name (UHID)DoctorModeCGST (₹)SGST (₹)Net Amount
${t.invoice_no}${t.sale_date}${t.patient_name} ${t.uhid ? '(' + t.uhid + ')' : ''}${t.doctor_name || 'N/A'}${t.payment_mode}₹${t.cgst_amount}₹${t.sgst_amount}₹${t.net_amount}
+ `; + openPrintReport(`Daybook Journal (${daybookFromDate} to ${daybookToDate})`, html); + }; + + // BANK AUDIT FUNCTIONS + const loadBankAudit = async (status = auditFilterStatus, search = auditSearch) => { + try { + const params = new URLSearchParams({ + store_id: store.store_id, + status: status, + search: search + }); + const res = await fetch(`${API_BASE}accounting/bank-reconciliation?${params.toString()}`); + const data = await res.json(); + if (data.status) setBankAuditData(data); + } catch (e) { + console.error(e); + } + }; + const handleReconcileSubmit = async (saleId, isReconciled) => { + setIsSubmittingAudit(true); + try { + const res = await fetch(API_BASE + 'accounting/reconcile-bank', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + sale_id: saleId, + is_reconciled: isReconciled ? 1 : 0, + reconciled_notes: auditNotes, + reconciled_by: auditorName + }) + }); + const data = await res.json(); + if (data.status) { + notify(data.message, 'success'); + setReconcilingSale(null); + setAuditNotes(''); + loadBankAudit(auditFilterStatus, auditSearch); + } else { + notify(data.message || 'Failed to update reconciliation', 'error'); + } + } catch (e) { + notify('Network error updating audit status: ' + e.message, 'error'); + } finally { + setIsSubmittingAudit(false); + } + }; + const exportBankCsv = () => { + if (!bankAuditData || !bankAuditData.transactions?.length) { + notify('No bank/UPI transactions to export.', 'warning'); + return; + } + const headers = ['Invoice No', 'Sale Date', 'Patient', 'Mode', 'Amount (Rs)', 'UPI Ref No', 'Card Ref No', 'Audit Status', 'Reconciled By', 'Notes']; + const bankTxns = bankAuditData.transactions || bankAuditData.records || []; + const rows = bankTxns.map(t => [t.invoice_no, t.sale_date, t.patient_name, t.payment_mode, t.net_amount, t.upi_ref_no || '', t.card_ref_no || '', t.is_reconciled == 1 ? 'RECONCILED' : 'PENDING', t.reconciled_by || '', t.reconciled_notes || '']); + downloadCsv(`Bank_UPI_Reconciliation_${todayStr}.csv`, [headers, ...rows]); + notify('Bank & UPI Audit CSV exported.', 'success'); + }; + const printBankAudit = () => { + if (!bankAuditData || !bankAuditData.transactions?.length) { + notify('No bank transactions to print.', 'warning'); + return; + } + const s = bankAuditData.summary || {}; + const html = ` +
+
Total UPI / Bank Sales: ₹${Number(s.total_amount || 0).toLocaleString('en-IN')} (${s.total_count} txns)
+
Verified / Reconciled: ₹${Number(s.reconciled_amount || 0).toLocaleString('en-IN')} (${s.reconciled_count})
+
Pending Verification: ₹${Number(s.pending_amount || 0).toLocaleString('en-IN')} (${s.pending_count})
+
+ + + + + + + + + + + + + + + ${(bankAuditData.transactions || bankAuditData.records || []).map(t => ` + + + + + + + + + + + `).join('')} + +
Invoice NoDatePatient NameModeAmountUPI / UTR RefStatusAudited By
${t.invoice_no}${t.sale_date}${t.patient_name}${t.payment_mode}₹${t.net_amount}${t.upi_ref_no || t.card_ref_no || 'N/A'}${t.is_reconciled == 1 ? 'VERIFIED' : 'PENDING'}${t.reconciled_by || 'Unverified'}
+ `; + openPrintReport('Bank & UPI Statement Audit Report', html); + }; + + // GST REPORT FUNCTIONS + const loadGst = async (m = gstMonth) => { + setLoadingGst(true); + try { + const res = await fetch(`${API_BASE}accounting/gst-report?store_id=${store.store_id}&month=${m}`); + const data = await res.json(); + if (data.status) setGstData(data); + } catch (e) { + console.error(e); + notify('Error loading GST report: ' + e.message, 'error'); + } finally { + setLoadingGst(false); + } + }; + const exportGstCsv = () => { + if (!gstData || !gstData.gstr1_sales?.length) { + notify('No GST data to export for this month.', 'warning'); + return; + } + const headers = ['HSN Code', 'GST Slab (%)', 'Taxable Value (Rs)', 'CGST (Rs)', 'SGST (Rs)', 'IGST (Rs)', 'Total Value (Rs)']; + const rows = gstData.gstr1_sales.map(g => [g.hsn_code, g.gst_rate, Number(g.taxable_val).toFixed(2), Number(g.cgst_val).toFixed(2), Number(g.sgst_val).toFixed(2), Number(g.igst_val).toFixed(2), Number(g.total_val).toFixed(2)]); + downloadCsv(`GSTR1_Report_${gstMonth}.csv`, [headers, ...rows]); + notify('GSTR-1 CSV exported successfully.', 'success'); + }; + + // SCHEDULE H1 REGISTER FUNCTIONS + const loadScheduleH1 = async (from = h1FromDate, to = h1ToDate, search = h1Search) => { + setLoadingH1(true); + try { + const params = new URLSearchParams({ + store_id: store.store_id, + from_date: from, + to_date: to, + search: search + }); + const res = await fetch(`${API_BASE}compliance/schedule-h1-register?${params.toString()}`); + const data = await res.json(); + if (data.status) setH1Records(data.records || []); + } catch (e) { + console.error(e); + } finally { + setLoadingH1(false); + } + }; + const exportH1Csv = () => { + if (!h1Records.length) { + notify('No Schedule H1 records to export.', 'warning'); + return; + } + const headers = ['Date', 'Bill No', 'Patient Name', 'Patient Address', 'Doctor Name', 'Doctor Reg No', 'Medicine Name', 'Batch No', 'Qty Supplied']; + const rows = h1Records.map(h => [h.sale_date, h.invoice_no, h.patient_name, h.patient_address || '', h.doctor_name, h.doctor_reg_no || '', h.item_name, h.batch_no, h.qty]); + downloadCsv(`Schedule_H1_Register_${h1FromDate}_to_${h1ToDate}.csv`, [headers, ...rows]); + notify('Schedule H1 Register CSV exported.', 'success'); + }; + const printH1Register = () => { + if (!h1Records.length) { + notify('No Schedule H1 records to print.', 'warning'); + return; + } + const html = ` +
+ Statutory Compliance: Mandatory Register under Drugs and Cosmetics (4th Amendment) Rules, 2013. Records must be retained for at least 3 years and open for inspection by Drug Inspector. +
+

Record Period: ${h1FromDate} to ${h1ToDate}

+ + + + + + + + + + + + + + ${h1Records.map(h => ` + + + + + + + + + + `).join('')} + +
DateBill NoPatient Name & AddressPrescribing Doctor & Reg NoSchedule H1 Drug NameBatch NoQty Dispensed
${h.sale_date.split(' ')[0]}${h.invoice_no}${h.patient_name} ${h.patient_address ? '
' + h.patient_address + '' : ''}
${h.doctor_name} ${h.doctor_reg_no ? '
Reg: ' + h.doctor_reg_no + '' : ''}
${h.item_name}${h.batch_no}${h.qty}
+ `; + openPrintReport('Statutory Schedule H1 Drug Register', html); + }; + + // CREDIT ACCOUNTS FUNCTIONS + const loadCreditAccounts = async () => { + setLoadingCredit(true); + try { + const res = await fetch(`${API_BASE}credit/accounts?store_id=${store.store_id}`); + const data = await res.json(); + if (data.status) setCreditAccounts(data.accounts || []); + } catch (e) { + console.error(e); + notify('Error loading credit accounts: ' + e.message, 'error'); + } finally { + setLoadingCredit(false); + } + }; + const handleSaveCreditAccount = async e => { + e.preventDefault(); + if (!accFormName.trim()) { + notify('Account / Person Name is required', 'error'); + return; + } + setIsSavingAccount(true); + try { + const res = await fetch(`${API_BASE}credit/save-account`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + account_type: accFormType, + account_name: accFormName.trim(), + phone: accFormPhone.trim(), + staff_id: accFormStaffId.trim(), + department: accFormDept.trim(), + credit_limit: Number(accFormLimit) || 0, + remarks: accFormRemarks.trim() + }) + }); + const data = await res.json(); + if (data.status) { + notify('Credit account created successfully.', 'success'); + setShowAddAccountModal(false); + setAccFormName(''); + setAccFormPhone(''); + setAccFormStaffId(''); + setAccFormDept(''); + setAccFormRemarks(''); + loadCreditAccounts(); + } else { + notify(data.message || 'Failed to create credit account', 'error'); + } + } catch (err) { + notify('Error: ' + err.message, 'error'); + } finally { + setIsSavingAccount(false); + } + }; + const openAccountLedger = async acc => { + setSelectedCreditAcc(acc); + setLoadingLedger(true); + try { + const res = await fetch(`${API_BASE}credit/ledger/${acc.account_id}?store_id=${store.store_id}`); + const data = await res.json(); + if (data.status) { + setCreditLedgerData(data); + } + } catch (e) { + notify('Error loading account ledger: ' + e.message, 'error'); + } finally { + setLoadingLedger(false); + } + }; + const openSettlePaymentModal = acc => { + setSelectedCreditAcc(acc); + setPayAmount(acc.current_balance > 0 ? String(acc.current_balance) : ''); + setPayMode('Cash'); + setPayRef(''); + setPayRemarks(''); + setShowPaymentModal(true); + }; + const handleRecordPayment = async e => { + e.preventDefault(); + const amt = Number(payAmount); + if (!amt || amt <= 0) { + notify('Please enter a valid payment amount.', 'error'); + return; + } + setIsRecordingPayment(true); + try { + const res = await fetch(`${API_BASE}credit/record-payment`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + account_id: selectedCreditAcc.account_id, + amount: amt, + payment_mode: payMode, + payment_ref: payRef.trim(), + remarks: payRemarks.trim(), + recorded_by_name: 'Accountant' + }) + }); + const data = await res.json(); + if (data.status) { + notify(`Settlement of ₹${amt} recorded successfully. New balance: ₹${data.new_balance}`, 'success'); + setShowPaymentModal(false); + loadCreditAccounts(); + if (selectedCreditAcc) { + openAccountLedger({ + ...selectedCreditAcc, + current_balance: data.new_balance + }); + } + } else { + notify(data.message || 'Failed to record payment', 'error'); + } + } catch (err) { + notify('Error recording payment: ' + err.message, 'error'); + } finally { + setIsRecordingPayment(false); + } + }; + const printAccountLedger = () => { + if (!creditLedgerData || !selectedCreditAcc) return; + const html = ` +
+
+
+ Account Name: ${selectedCreditAcc.account_name} (${selectedCreditAcc.account_type.toUpperCase()})
+ Phone: ${selectedCreditAcc.phone || 'N/A'}
+ Dept / Staff ID: ${selectedCreditAcc.department || ''} ${selectedCreditAcc.staff_id ? '(' + selectedCreditAcc.staff_id + ')' : ''} +
+
+ Credit Limit: ₹${Number(selectedCreditAcc.credit_limit || 0).toLocaleString('en-IN')}
+ Current Outstanding: ₹${Number(selectedCreditAcc.current_balance || 0).toLocaleString('en-IN')} +
+
+
+ + + + + + + + + + + + + + ${creditLedgerData.entries.map(e => ` + + + + + + + + + + `).join('')} + +
DateTypeInvoice / Ref NoDebit (Bills)Credit (Payments)Balance AfterRecorded By / Remarks
${e.created_at}${e.entry_type === 'DEBIT' ? 'BILL DEBIT' : 'PAYMENT'}${e.invoice_no || e.payment_ref || '-'}${Number(e.debit_amount) > 0 ? '₹' + Number(e.debit_amount).toFixed(2) : '-'}${Number(e.credit_amount) > 0 ? '₹' + Number(e.credit_amount).toFixed(2) : '-'}₹${Number(e.balance_after).toFixed(2)}${e.remarks || ''} (${e.recorded_by_name || 'Staff'})
+ `; + openPrintReport(`Credit Account Statement - ${selectedCreditAcc.account_name}`, html); + }; + + // Filtered credit accounts + const filteredCreditAccounts = creditAccounts.filter(acc => { + if (!creditSearch) return true; + const q = creditSearch.toLowerCase(); + return acc.account_name && acc.account_name.toLowerCase().includes(q) || acc.phone && acc.phone.includes(q) || acc.staff_id && acc.staff_id.toLowerCase().includes(q) || acc.department && acc.department.toLowerCase().includes(q); + }); + const totalOutstandingCredit = creditAccounts.reduce((sum, a) => sum + Number(a.current_balance || 0), 0); + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-2 mb-3", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${accTab === 'daybook' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setAccTab('daybook'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-check me-1" + }), " Daily Cash Book / Day Book"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${accTab === 'bank_audit' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setAccTab('bank_audit'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-bank2 me-1" + }), " Bank & UPI Statement Audit"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${accTab === 'gst' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setAccTab('gst'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-spreadsheet me-1" + }), " GST Returns (GSTR-1 & 2)"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${accTab === 'schedule_h1' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setAccTab('schedule_h1'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " Statutory Schedule H1 Register"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm ${accTab === 'credit_accounts' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => setAccTab('credit_accounts'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-people-fill me-1" + }), " Staff & Customer Credit Accounts", totalOutstandingCredit > 0 && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger rounded-pill ms-1.5", + style: { + fontSize: '0.65rem' + }, + children: ["₹", totalOutstandingCredit.toLocaleString('en-IN')] + })] + })] + }), accTab === 'daybook' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark small", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-funnel text-primary me-1" + }), " Quick Filter:"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-1 px-2.5", + onClick: () => handleDaybookFilterPreset('today'), + children: "Today" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-1 px-2.5", + onClick: () => handleDaybookFilterPreset('yesterday'), + children: "Yesterday" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-1 px-2.5", + onClick: () => handleDaybookFilterPreset('last7'), + children: "Last 7 Days" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-1 px-2.5", + onClick: () => handleDaybookFilterPreset('month'), + children: "This Month" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2 flex-wrap", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("label", { + className: "small text-muted mb-0", + children: "From:" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: daybookFromDate, + onChange: e => setDaybookFromDate(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("label", { + className: "small text-muted mb-0", + children: "To:" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: daybookToDate, + onChange: e => setDaybookToDate(e.target.value) + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-primary px-3 fw-bold", + onClick: () => loadDaybook(daybookFromDate, daybookToDate), + disabled: loadingDaybook, + children: loadingDaybook ? 'Loading...' : 'Apply' + }), /*#__PURE__*/_jsxs("div", { + className: "border-start ps-2 d-flex gap-1.5", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-dark px-2.5 d-flex align-items-center gap-1", + onClick: printDaybook, + title: "Print Daybook Statement", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer" + }), " Print"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-success px-2.5 d-flex align-items-center gap-1", + onClick: exportDaybookCsv, + title: "Download Excel / CSV", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-excel" + }), " Export CSV"] + })] + })] + })] + }) + }), daybookData && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-success shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "TOTAL PERIOD SALES" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-dark mt-1", + children: ["₹", Number(daybookData.summary.total_sales || 0).toLocaleString('en-IN')] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [daybookData.summary.total_invoices, " Bills"] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-primary shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "CASH IN DRAWER" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-primary mt-1", + children: ["₹", Number(daybookData.summary.cash_in_drawer || 0).toLocaleString('en-IN')] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-warning shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "UPI / QR COLLECTIONS" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-warning mt-1", + children: ["₹", Number(daybookData.summary.upi_collection || 0).toLocaleString('en-IN')] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-3 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-danger shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "CREDIT BILLED (IPD + STAFF)" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-danger mt-1", + children: ["₹", Number(daybookData.summary.ipd_credit || 0).toLocaleString('en-IN')] + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "counter-card p-0 overflow-hidden shadow-sm", + children: [/*#__PURE__*/_jsxs("div", { + className: "p-3 border-bottom d-flex justify-content-between align-items-center bg-light", + children: [/*#__PURE__*/_jsxs("h6", { + className: "mb-0 fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-receipt text-primary me-1" + }), " Transactions Journal (", daybookFromDate, " to ", daybookToDate, ")"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary", + children: [daybookData.transactions.length, " Records"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Invoice No" + }), /*#__PURE__*/_jsx("th", { + children: "Date & Time" + }), /*#__PURE__*/_jsx("th", { + children: "Patient (UHID)" + }), /*#__PURE__*/_jsx("th", { + children: "Doctor" + }), /*#__PURE__*/_jsx("th", { + children: "Mode" + }), /*#__PURE__*/_jsx("th", { + children: "CGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "SGST (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Net Amount" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: daybookData.transactions.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No transactions found for the selected date range." + }) + }) : daybookData.transactions.map(t => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-bold", + children: t.invoice_no + }), /*#__PURE__*/_jsx("td", { + children: t.sale_date + }), /*#__PURE__*/_jsxs("td", { + children: [t.patient_name, " ", t.uhid ? `(${t.uhid})` : ''] + }), /*#__PURE__*/_jsx("td", { + children: t.doctor_name + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: t.payment_mode + }) + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", t.cgst_amount] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", t.sgst_amount] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold text-success", + children: ["₹", t.net_amount] + })] + }, t.sale_id)) + })] + }) + })] + })] + })] + }), accTab === 'bank_audit' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-4 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-primary shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "TOTAL ONLINE / UPI SALES" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-dark mt-1", + children: ["₹", Number(bankAuditData?.summary?.total_amount || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [bankAuditData?.summary?.total_count || 0, " Transactions Recorded"] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-success shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-success fw-bold", + children: "STATEMENT RECONCILED (VERIFIED)" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-success mt-1", + children: ["₹", Number(bankAuditData?.summary?.reconciled_amount || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-success", + children: [bankAuditData?.summary?.reconciled_count || 0, " Bills Matched with Bank"] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-warning shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-warning fw-bold", + children: "PENDING AUDIT VERIFICATION" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-warning mt-1", + children: ["₹", Number(bankAuditData?.summary?.pending_amount || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsxs("small", { + className: "text-warning", + children: [bankAuditData?.summary?.pending_count || 0, " Bills Unverified"] + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2 align-items-center", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-5", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn ${auditFilterStatus === 'all' ? 'btn-primary' : 'btn-outline-secondary'}`, + onClick: () => { + setAuditFilterStatus('all'); + loadBankAudit('all', auditSearch); + }, + children: ["All (", bankAuditData?.summary?.total_count || 0, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${auditFilterStatus === 'pending' ? 'btn-warning text-dark fw-bold' : 'btn-outline-secondary'}`, + onClick: () => { + setAuditFilterStatus('pending'); + loadBankAudit('pending', auditSearch); + }, + children: ["Pending Verification (", bankAuditData?.summary?.pending_count || 0, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn ${auditFilterStatus === 'reconciled' ? 'btn-success fw-bold' : 'btn-outline-secondary'}`, + onClick: () => { + setAuditFilterStatus('reconciled'); + loadBankAudit('reconciled', auditSearch); + }, + children: ["Reconciled (", bankAuditData?.summary?.reconciled_count || 0, ")"] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "Search by Bill No, UTR / UPI Ref...", + value: auditSearch, + onChange: e => { + setAuditSearch(e.target.value); + loadBankAudit(auditFilterStatus, e.target.value); + } + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3 text-end d-flex gap-1.5 justify-content-end", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-dark", + onClick: printBankAudit, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-success", + onClick: exportBankCsv, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-excel me-1" + }), " Export CSV"] + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-0 overflow-hidden shadow-sm", + children: /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Invoice No" + }), /*#__PURE__*/_jsx("th", { + children: "Date & Time" + }), /*#__PURE__*/_jsx("th", { + children: "Patient" + }), /*#__PURE__*/_jsx("th", { + children: "Mode" + }), /*#__PURE__*/_jsx("th", { + children: "Bill Total" + }), /*#__PURE__*/_jsx("th", { + children: "Bank / UTR Reference" + }), /*#__PURE__*/_jsx("th", { + children: "Audit Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Action" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: (() => { + const txns = bankAuditData?.transactions || bankAuditData?.records || []; + if (!bankAuditData) { + return /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary me-2" + }), "Loading bank audit records..."] + }) + }); + } + if (txns.length === 0) { + return /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No transactions found matching the filter." + }) + }); + } + return txns.map(t => /*#__PURE__*/_jsxs("tr", { + className: t.is_reconciled == 1 ? 'bg-success-subtle' : '', + children: [/*#__PURE__*/_jsx("td", { + className: "fw-bold", + children: t.invoice_no + }), /*#__PURE__*/_jsx("td", { + children: t.sale_date + }), /*#__PURE__*/_jsx("td", { + children: t.patient_name + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: t.payment_mode + }) + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold text-primary", + children: ["₹", t.net_amount] + }), /*#__PURE__*/_jsx("td", { + children: t.upi_ref_no ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-info text-dark", + children: "UPI" + }), " ", /*#__PURE__*/_jsx("code", { + children: t.upi_ref_no + })] + }) : t.card_ref_no ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("span", { + className: "badge bg-primary", + children: "CARD" + }), " ", /*#__PURE__*/_jsx("code", { + children: t.card_ref_no + })] + }) : /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "Direct QR" + }) + }), /*#__PURE__*/_jsx("td", { + children: t.is_reconciled == 1 ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-success", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle me-1" + }), " Reconciled"] + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted mt-0.5", + children: [t.reconciled_by, " • ", t.reconciled_at?.split(' ')[0]] + })] + }) : /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock me-1" + }), " Pending Statement"] + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end", + children: t.is_reconciled == 1 ? /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-danger py-0.5 px-2", + style: { + fontSize: '0.75rem' + }, + onClick: () => handleReconcileSubmit(t.sale_id, 0), + children: "Un-reconcile" + }) : /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-success py-0.5 px-2.5 fw-bold", + style: { + fontSize: '0.75rem' + }, + onClick: () => { + setReconcilingSale(t); + setAuditNotes(''); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check2-circle me-1" + }), " Verify Entry"] + }) + })] + }, t.sale_id)); + })() + })] + }) + }) + }), reconcilingSale && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + tabIndex: "-1", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.7)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content shadow-lg border-0", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-bank me-2 text-primary" + }), " Reconcile Bank / UPI Statement"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setReconcilingSale(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card bg-light border p-2.5 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "Invoice No:" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold text-dark", + children: reconcilingSale.invoice_no + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "Amount:" + }), /*#__PURE__*/_jsxs("span", { + className: "fw-bold text-success fs-6", + children: ["₹", reconcilingSale.net_amount] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "Recorded Ref / UTR:" + }), /*#__PURE__*/_jsx("code", { + children: reconcilingSale.upi_ref_no || reconcilingSale.card_ref_no || 'Direct Store QR' + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Audited By (Accountant / User)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: auditorName, + onChange: e => setAuditorName(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Accountant Statement Audit Note" + }), /*#__PURE__*/_jsx("textarea", { + className: "form-control form-control-sm", + rows: "2", + value: auditNotes, + onChange: e => setAuditNotes(e.target.value), + placeholder: "e.g. Matched in Bank A/c statement entry on 08-Sep-2026, Credit Ref verified" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-light", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setReconcilingSale(null), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-success fw-bold", + onClick: () => handleReconcileSubmit(reconcilingSale.sale_id, 1), + disabled: isSubmittingAudit, + children: isSubmittingAudit ? 'Saving...' : 'Mark Verified with Statement' + })] + })] + }) + }) + })] + }), accTab === 'gst' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("label", { + className: "small fw-bold text-dark mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-month text-primary me-1" + }), " Return Filing Month:"] + }), /*#__PURE__*/_jsx("input", { + type: "month", + className: "form-control form-control-sm", + value: gstMonth, + onChange: e => { + setGstMonth(e.target.value); + loadGst(e.target.value); + } + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-primary px-3 fw-bold", + onClick: () => loadGst(gstMonth), + disabled: loadingGst, + children: loadingGst ? 'Loading...' : 'Refresh' + })] + }), /*#__PURE__*/_jsx("div", { + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-success px-3 fw-bold d-flex align-items-center gap-1.5", + onClick: exportGstCsv, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-excel" + }), " Export GSTR-1 Excel / CSV"] + }) + })] + }) + }), gstData && /*#__PURE__*/_jsxs("div", { + className: "counter-card mb-3 shadow-sm", + children: [/*#__PURE__*/_jsxs("div", { + className: "p-3 border-bottom d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-spreadsheet text-primary me-1" + }), " GSTR-1 Outward Sales Summary (HSN-wise) for ", gstMonth] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary", + children: ["GSTIN: ", store.gst_no || 'N/A'] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "HSN Code" + }), /*#__PURE__*/_jsx("th", { + children: "GST Slab" + }), /*#__PURE__*/_jsx("th", { + children: "Taxable Value (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "CGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "SGST (₹)" + }), /*#__PURE__*/_jsx("th", { + children: "IGST (₹)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Total Invoice Value (₹)" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: gstData.gstr1_sales.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsxs("td", { + colSpan: "7", + className: "text-center py-4 text-muted", + children: ["No sales recorded for GST filing in month ", gstMonth, "."] + }) + }) : gstData.gstr1_sales.map((g, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("code", { + children: g.hsn_code + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary", + children: [g.gst_rate, "%"] + }) + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", Number(g.taxable_val).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", Number(g.cgst_val).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", Number(g.sgst_val).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + children: ["₹", Number(g.igst_val).toFixed(2)] + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", Number(g.total_val).toFixed(2)] + })] + }, i)) + })] + }) + })] + })] + }), accTab === 'schedule_h1' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2 flex-wrap", + children: [/*#__PURE__*/_jsxs("span", { + className: "small fw-bold text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-funnel text-success me-1" + }), " Date Filter:"] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: h1FromDate, + onChange: e => setH1FromDate(e.target.value) + }), /*#__PURE__*/_jsx("span", { + children: "to" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: h1ToDate, + onChange: e => setH1ToDate(e.target.value) + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-primary fw-bold", + onClick: () => loadScheduleH1(h1FromDate, h1ToDate, h1Search), + disabled: loadingH1, + children: loadingH1 ? 'Loading...' : 'Filter' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "Search medicine or doctor...", + value: h1Search, + onChange: e => { + setH1Search(e.target.value); + loadScheduleH1(h1FromDate, h1ToDate, e.target.value); + } + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-dark", + onClick: printH1Register, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-printer me-1" + }), " Print"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-success", + onClick: exportH1Csv, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-excel me-1" + }), " Export CSV"] + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "counter-card shadow-sm", + children: [/*#__PURE__*/_jsxs("div", { + className: "p-3 border-bottom d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check text-success me-1" + }), " Statutory Schedule H1 Drug Register"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Mandatory under Indian Drugs & Cosmetics Rules (4th Amendment 2013). Retain for 3 years." + })] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger", + children: [h1Records.length, " Dispensed Entries"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos table-bordered mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Date" + }), /*#__PURE__*/_jsx("th", { + children: "Bill No" + }), /*#__PURE__*/_jsx("th", { + children: "Patient Name & Address" + }), /*#__PURE__*/_jsx("th", { + children: "Prescribing Doctor & Reg No" + }), /*#__PURE__*/_jsx("th", { + children: "Medicine Name" + }), /*#__PURE__*/_jsx("th", { + children: "Batch No" + }), /*#__PURE__*/_jsx("th", { + children: "Qty Supplied" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: h1Records.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "7", + className: "text-center py-4 text-muted", + children: "No Schedule H1 medicines dispensed in this period." + }) + }) : h1Records.map((h, i) => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: h.sale_date?.split(' ')[0] + }), /*#__PURE__*/_jsx("td", { + className: "fw-bold", + children: h.invoice_no + }), /*#__PURE__*/_jsxs("td", { + children: [h.patient_name, " ", h.patient_address ? `(${h.patient_address})` : ''] + }), /*#__PURE__*/_jsxs("td", { + children: [h.doctor_name, " ", h.doctor_reg_no ? `(Reg: ${h.doctor_reg_no})` : ''] + }), /*#__PURE__*/_jsx("td", { + className: "fw-bold text-danger", + children: h.item_name + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("code", { + children: h.batch_no + }) + }), /*#__PURE__*/_jsx("td", { + className: "fw-bold", + children: h.qty + })] + }, i)) + })] + }) + })] + })] + }), accTab === 'credit_accounts' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-4 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-primary shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "TOTAL REGISTERED ACCOUNTS" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-dark mt-1", + children: [creditAccounts.length, " Accounts"] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "Staff, Doctors, Institutional & Patients" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-danger shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-danger fw-bold", + children: "TOTAL OUTSTANDING DUES" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-danger mt-1", + children: ["₹", totalOutstandingCredit.toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-danger", + children: "Unsettled Pharmacy Debits" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4 col-sm-6", + children: /*#__PURE__*/_jsxs("div", { + className: "counter-card p-3 border-start border-4 border-success shadow-sm", + children: [/*#__PURE__*/_jsx("small", { + className: "text-success fw-bold", + children: "TOTAL CREDIT LIMIT SANCTIONED" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bolder text-success mt-1", + children: ["₹", creditAccounts.reduce((sum, a) => sum + Number(a.credit_limit || 0), 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-success", + children: "Authorized Spending Cap" + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-3 mb-3 shadow-sm", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-3", + children: [/*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center gap-2 flex-grow-1", + style: { + maxWidth: 420 + }, + children: /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "Search by name, phone, dept, staff ID...", + value: creditSearch, + onChange: e => setCreditSearch(e.target.value) + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center gap-2", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-primary px-3 py-1.5 fw-bold shadow-sm d-flex align-items-center gap-1.5", + onClick: () => setShowAddAccountModal(true), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-plus-fill" + }), " New Credit Account"] + }) + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "counter-card p-0 overflow-hidden shadow-sm", + children: /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos mb-0", + children: [/*#__PURE__*/_jsx("thead", { + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Account / Person Name" + }), /*#__PURE__*/_jsx("th", { + children: "Account Type" + }), /*#__PURE__*/_jsx("th", { + children: "Dept / Staff ID" + }), /*#__PURE__*/_jsx("th", { + children: "Phone" + }), /*#__PURE__*/_jsx("th", { + children: "Credit Limit" + }), /*#__PURE__*/_jsx("th", { + children: "Current Balance" + }), /*#__PURE__*/_jsx("th", { + children: "Status" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Actions" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: loadingCredit ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "Loading credit accounts..." + }) + }) : filteredCreditAccounts.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No credit accounts found. Click \"New Credit Account\" to create one." + }) + }) : filteredCreditAccounts.map(acc => { + const typeColor = acc.account_type === 'staff' ? 'primary' : acc.account_type === 'doctor' ? 'success' : acc.account_type === 'corporate' ? 'dark' : 'warning'; + const bal = Number(acc.current_balance || 0); + return /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsxs("td", { + className: "fw-bold text-dark", + children: [acc.account_name, acc.remarks && /*#__PURE__*/_jsx("small", { + className: "d-block text-muted", + children: acc.remarks + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge bg-${typeColor}-subtle text-${typeColor} border border-${typeColor} text-uppercase px-2`, + style: { + fontSize: '0.65rem' + }, + children: acc.account_type + }) + }), /*#__PURE__*/_jsx("td", { + children: acc.department || acc.staff_id || '-' + }), /*#__PURE__*/_jsx("td", { + children: acc.phone || '-' + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: ["₹", Number(acc.credit_limit || 0).toLocaleString('en-IN')] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("span", { + className: `fw-bold fs-6 ${bal > 0 ? 'text-danger' : 'text-success'}`, + children: ["₹", bal.toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge ${acc.is_active == 1 ? 'bg-success' : 'bg-secondary'}`, + children: acc.is_active == 1 ? 'ACTIVE' : 'INACTIVE' + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end", + children: /*#__PURE__*/_jsxs("div", { + className: "btn-group btn-group-sm", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-outline-primary py-0.5 px-2", + style: { + fontSize: '0.75rem' + }, + onClick: () => openAccountLedger(acc), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-text me-1" + }), " Ledger"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-outline-success py-0.5 px-2 fw-bold", + style: { + fontSize: '0.75rem' + }, + onClick: () => openSettlePaymentModal(acc), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-coin me-1" + }), " Settle"] + })] + }) + })] + }, acc.account_id); + }) + })] + }) + }) + }), showAddAccountModal && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + tabIndex: "-1", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.7)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + children: /*#__PURE__*/_jsx("div", { + className: "modal-content shadow-lg border-0", + children: /*#__PURE__*/_jsxs("form", { + onSubmit: handleSaveCreditAccount, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-plus-fill text-primary me-2" + }), " Create Credit Account"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowAddAccountModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Account Type" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: accFormType, + onChange: e => setAccFormType(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "staff", + children: "Staff Member" + }), /*#__PURE__*/_jsx("option", { + value: "doctor", + children: "Consultant / Doctor" + }), /*#__PURE__*/_jsx("option", { + value: "corporate", + children: "Hospital Trust / Corporate" + }), /*#__PURE__*/_jsx("option", { + value: "customer", + children: "Regular Customer / VIP" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Credit Limit (₹)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm", + value: accFormLimit, + onChange: e => setAccFormLimit(e.target.value), + placeholder: "5000" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Person / Organization Name ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + required: true, + value: accFormName, + onChange: e => setAccFormName(e.target.value), + placeholder: "e.g. Dr. Rajesh Sharma / Sister Sunita" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Phone Number" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: accFormPhone, + onChange: e => setAccFormPhone(e.target.value), + placeholder: "e.g. 9876543210" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Staff ID / Employee Code" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: accFormStaffId, + onChange: e => setAccFormStaffId(e.target.value), + placeholder: "e.g. EMP-1042" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Department" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: accFormDept, + onChange: e => setAccFormDept(e.target.value), + placeholder: "e.g. ICU Nursing / General Surgery / Administration" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Remarks / Terms" + }), /*#__PURE__*/_jsx("textarea", { + className: "form-control form-control-sm", + rows: "2", + value: accFormRemarks, + onChange: e => setAccFormRemarks(e.target.value), + placeholder: "e.g. Deducted monthly from hospital payroll or settled at month end" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-light", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setShowAddAccountModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-sm btn-primary fw-bold", + disabled: isSavingAccount, + children: isSavingAccount ? 'Creating...' : 'Create Account' + })] + })] + }) + }) + }) + }), selectedCreditAcc && creditLedgerData && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + tabIndex: "-1", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.7)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-xl", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content shadow-lg border-0", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-journal-text text-primary fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0", + children: [selectedCreditAcc.account_name, " — Credit Statement"] + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [selectedCreditAcc.account_type.toUpperCase(), " • ", selectedCreditAcc.department || 'General'] + })] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => { + setSelectedCreditAcc(null); + setCreditLedgerData(null); + } + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsx("div", { + className: "card p-3 mb-3 bg-light border", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2 align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("small", { + className: "text-muted fw-bold", + children: "CREDIT LIMIT" + }), /*#__PURE__*/_jsxs("h5", { + className: "fw-bold mb-0", + children: ["₹", Number(selectedCreditAcc.credit_limit || 0).toLocaleString('en-IN')] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("small", { + className: "text-danger fw-bold", + children: "OUTSTANDING BALANCE" + }), /*#__PURE__*/_jsxs("h4", { + className: "fw-bold text-danger mb-0", + children: ["₹", Number(selectedCreditAcc.current_balance || 0).toLocaleString('en-IN', { + minimumFractionDigits: 2 + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3", + children: [/*#__PURE__*/_jsx("small", { + className: "text-success fw-bold", + children: "AVAILABLE CREDIT" + }), /*#__PURE__*/_jsxs("h5", { + className: "fw-bold text-success mb-0", + children: ["₹", Math.max(0, Number(selectedCreditAcc.credit_limit || 0) - Number(selectedCreditAcc.current_balance || 0)).toLocaleString('en-IN')] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-3 text-end", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-success fw-bold px-3 py-1.5 shadow-sm me-2", + onClick: () => openSettlePaymentModal(selectedCreditAcc), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-stack me-1" + }), " Settle Payment"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-dark px-2.5 py-1.5", + onClick: printAccountLedger, + title: "Print Account Statement", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-printer" + }) + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + style: { + maxHeight: 380, + overflowY: 'auto' + }, + children: /*#__PURE__*/_jsxs("table", { + className: "table table-pos table-bordered mb-0", + children: [/*#__PURE__*/_jsx("thead", { + className: "table-dark sticky-top", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Timestamp" + }), /*#__PURE__*/_jsx("th", { + children: "Type" + }), /*#__PURE__*/_jsx("th", { + children: "Invoice / Receipt Ref" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Debit (Bills)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Credit (Payments)" + }), /*#__PURE__*/_jsx("th", { + className: "text-end", + children: "Running Balance" + }), /*#__PURE__*/_jsx("th", { + children: "Mode" + }), /*#__PURE__*/_jsx("th", { + children: "Recorded By / Notes" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: creditLedgerData.entries.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "8", + className: "text-center py-4 text-muted", + children: "No transactions on this account yet." + }) + }) : creditLedgerData.entries.map(ent => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + children: ent.created_at + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge ${ent.entry_type === 'DEBIT' ? 'bg-danger' : 'bg-success'}`, + children: ent.entry_type + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("strong", { + children: ent.invoice_no || ent.payment_ref || '-' + }) + }), /*#__PURE__*/_jsx("td", { + className: "text-end fw-bold text-danger", + children: Number(ent.debit_amount) > 0 ? '₹' + Number(ent.debit_amount).toFixed(2) : '-' + }), /*#__PURE__*/_jsx("td", { + className: "text-end fw-bold text-success", + children: Number(ent.credit_amount) > 0 ? '₹' + Number(ent.credit_amount).toFixed(2) : '-' + }), /*#__PURE__*/_jsxs("td", { + className: "text-end fw-bold", + children: ["₹", Number(ent.balance_after).toFixed(2)] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + children: ent.payment_mode + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [ent.remarks || 'Bill Charge', " (", ent.recorded_by_name || 'System', ")"] + }) + })] + }, ent.ledger_id)) + })] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "modal-footer py-2 px-3 bg-light", + children: /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => { + setSelectedCreditAcc(null); + setCreditLedgerData(null); + }, + children: "Close Statement" + }) + })] + }) + }) + }), showPaymentModal && selectedCreditAcc && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + tabIndex: "-1", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.7)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + children: /*#__PURE__*/_jsx("div", { + className: "modal-content shadow-lg border-0", + children: /*#__PURE__*/_jsxs("form", { + onSubmit: handleRecordPayment, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cash-coin text-success me-2" + }), " Record Credit Settlement Payment"] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowPaymentModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card bg-light border p-2.5 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between mb-1", + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "Account:" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold text-dark", + children: selectedCreditAcc.account_name + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between", + children: [/*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "Total Outstanding Due:" + }), /*#__PURE__*/_jsxs("span", { + className: "fw-bold text-danger fs-6", + children: ["₹", Number(selectedCreditAcc.current_balance || 0).toFixed(2)] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Settlement Amount Received (₹) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light fw-bold", + children: "₹" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.01", + className: "form-control form-control-sm fs-6 fw-bold text-success", + required: true, + value: payAmount, + onChange: e => setPayAmount(e.target.value), + placeholder: "Enter amount" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-outline-secondary", + onClick: () => setPayAmount(String(selectedCreditAcc.current_balance)), + children: "Full Pay" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Payment Method" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: payMode, + onChange: e => setPayMode(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "Cash", + children: "Cash in Drawer" + }), /*#__PURE__*/_jsx("option", { + value: "UPI", + children: "UPI / QR Code" + }), /*#__PURE__*/_jsx("option", { + value: "Bank", + children: "Direct Bank Transfer / NEFT" + }), /*#__PURE__*/_jsx("option", { + value: "Salary_Deduction", + children: "Payroll / Salary Deduction" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Receipt / UTR / Ref No" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: payRef, + onChange: e => setPayRef(e.target.value), + placeholder: "e.g. UTR-991823" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Remarks / Receipt Note" + }), /*#__PURE__*/_jsx("textarea", { + className: "form-control form-control-sm", + rows: "2", + value: payRemarks, + onChange: e => setPayRemarks(e.target.value), + placeholder: "e.g. Cash received at pharmacy counter by cashier" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-light", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setShowPaymentModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-sm btn-success fw-bold", + disabled: isRecordingPayment, + children: isRecordingPayment ? 'Recording...' : 'Confirm Payment & Update Balance' + })] + })] + }) + }) + }) + })] + })] + }); +} +function StaffManagementView({ + store, + notify, + activeOperator, + onOperatorUpdated, + onSelectOperator +}) { + if (!store) return null; + const [staffList, setStaffList] = useState([]); + const [loading, setLoading] = useState(false); + + // Modal state for Add/Edit Staff + const [showEditModal, setShowEditModal] = useState(false); + const [editingUser, setEditingUser] = useState(null); + const [formFullName, setFormFullName] = useState(''); + const [formUsername, setFormUsername] = useState(''); + const [formPinCode, setFormPinCode] = useState(''); + const [formRole, setFormRole] = useState('pharmacist'); + const [formPhone, setFormPhone] = useState(''); + const [formRegNo, setFormRegNo] = useState(''); + const [formHprId, setFormHprId] = useState(''); + const [formIsDefault, setFormIsDefault] = useState(false); + const [formIsActive, setFormIsActive] = useState(true); + const [isSaving, setIsSaving] = useState(false); + + // 6 Granular Permissions Matrix + const defaultPermissions = { + admin: false, + sale: true, + purchase: false, + sale_edit_after_1h: false, + purchase_edit_verified: false, + bank_upi_audit: false + }; + const [formPermissions, setFormPermissions] = useState(defaultPermissions); + const applyRoleDefaults = role => { + setFormRole(role); + if (role === 'store_manager') { + setFormPermissions({ + admin: true, + sale: true, + purchase: true, + sale_edit_after_1h: true, + purchase_edit_verified: true, + bank_upi_audit: true + }); + } else if (role === 'pharmacist') { + setFormPermissions({ + admin: false, + sale: true, + purchase: true, + sale_edit_after_1h: false, + purchase_edit_verified: false, + bank_upi_audit: false + }); + } else if (role === 'cashier') { + setFormPermissions({ + admin: false, + sale: true, + purchase: false, + sale_edit_after_1h: false, + purchase_edit_verified: false, + bank_upi_audit: false + }); + } else if (role === 'auditor') { + setFormPermissions({ + admin: false, + sale: false, + purchase: false, + sale_edit_after_1h: false, + purchase_edit_verified: false, + bank_upi_audit: true + }); + } + }; + useEffect(() => { + if (store?.store_id) { + loadStaff(); + } + }, [store?.store_id]); + const loadStaff = async () => { + setLoading(true); + try { + const res = await fetch(`${API_BASE}users?store_id=${store.store_id}`); + const data = await res.json(); + if (data.status) { + setStaffList(data.users || []); + } + } catch (e) { + console.error("Failed to load staff:", e); + } finally { + setLoading(false); + } + }; + const openAddModal = () => { + setEditingUser(null); + setFormFullName(''); + setFormUsername(''); + setFormPinCode('1234'); + applyRoleDefaults('pharmacist'); + setFormPhone(''); + setFormRegNo(''); + setFormHprId(''); + setFormIsDefault(false); + setFormIsActive(true); + setShowEditModal(true); + }; + const openEditModal = user => { + setEditingUser(user); + setFormFullName(user.full_name || ''); + setFormUsername(user.username || ''); + setFormPinCode(''); // Keep empty unless resetting + setFormRole(user.user_role || 'pharmacist'); + setFormPhone(user.phone || ''); + setFormRegNo(user.pharmacist_reg_no || ''); + setFormHprId(user.pharmacist_hpr_id || ''); + setFormIsDefault(user.is_default == 1); + setFormIsActive(user.is_active == 1); + + // Parse permissions + let perms = { + ...defaultPermissions + }; + if (user.permissions) { + try { + const parsed = typeof user.permissions === 'string' ? JSON.parse(user.permissions) : user.permissions; + perms = { + ...defaultPermissions, + ...parsed + }; + } catch (e) { + console.warn('Error parsing user permissions:', e); + } + } + setFormPermissions(perms); + setShowEditModal(true); + }; + const togglePermission = key => { + setFormPermissions(prev => ({ + ...prev, + [key]: !prev[key] + })); + }; + const handleSaveStaff = async e => { + e.preventDefault(); + if (!formFullName.trim() || !formUsername.trim()) { + notify('Full Name and Username are required.', 'error'); + return; + } + setIsSaving(true); + try { + const payload = { + user_id: editingUser ? editingUser.user_id : 0, + store_id: store.store_id, + full_name: formFullName.trim(), + username: formUsername.trim(), + user_role: formRole, + phone: formPhone.trim(), + pharmacist_reg_no: formRegNo.trim(), + pharmacist_hpr_id: formHprId.trim(), + is_default: formIsDefault ? 1 : 0, + is_active: formIsActive ? 1 : 0, + permissions: JSON.stringify(formPermissions) + }; + if (formPinCode.trim()) { + payload.pin_code = formPinCode.trim(); + } + const res = await fetch(`${API_BASE}users/save`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const data = await res.json(); + if (data.status) { + notify('Staff profile and permission matrix saved successfully.', 'success'); + setShowEditModal(false); + loadStaff(); + if (onOperatorUpdated) onOperatorUpdated(); + } else { + notify(data.message || 'Failed to save staff profile.', 'error'); + } + } catch (err) { + notify('Network error saving staff profile.', 'error'); + } finally { + setIsSaving(false); + } + }; + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap align-items-center justify-content-between gap-3 mb-4 pb-3 border-bottom", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("h5", { + className: "fw-bolder text-dark mb-1 d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-lock-fill text-primary" + }), " Medical Store Staff & 6-Tier Permission Matrix"] + }), /*#__PURE__*/_jsxs("p", { + className: "text-muted small mb-0", + children: ["Manage pharmacy staff credentials, cashier PINs, and granular audit/sale/purchase rights for ", /*#__PURE__*/_jsx("strong", { + children: store.store_name + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "d-flex align-items-center gap-2", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-primary px-3 py-2 fw-bold shadow-sm d-flex align-items-center gap-1.5", + onClick: openAddModal, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-plus-fill" + }), " Add Staff Member"] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "row g-3", + children: loading ? /*#__PURE__*/_jsxs("div", { + className: "col-12 text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hourglass-split fs-3 d-block mb-2 text-primary" + }), " Loading staff profiles..."] + }) : staffList.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "col-12 text-center py-5 text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-people fs-3 d-block mb-1 text-secondary" + }), "No staff members assigned to this store yet. Click \"Add Staff Member\" to get started."] + }) : staffList.map(user => { + const isCurrent = activeOperator?.user_id == user.user_id; + const roleColor = user.user_role === 'store_manager' ? 'primary' : user.user_role === 'pharmacist' ? 'success' : user.user_role === 'auditor' ? 'info' : user.user_role === 'cashier' ? 'warning' : 'secondary'; + let perms = {}; + try { + perms = typeof user.permissions === 'string' ? JSON.parse(user.permissions || '{}') : user.permissions || {}; + } catch (e) { + perms = {}; + } + return /*#__PURE__*/_jsx("div", { + className: "col-md-6 col-lg-4", + children: /*#__PURE__*/_jsxs("div", { + className: `counter-card p-3 h-100 position-relative border-start border-4 border-${roleColor} shadow-sm`, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-start justify-content-between gap-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: `rounded-circle bg-${roleColor}-subtle text-${roleColor} fw-bold d-flex align-items-center justify-content-center`, + style: { + width: 42, + height: 42, + fontSize: '1rem' + }, + children: user.full_name ? user.full_name[0] : 'U' + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "fw-bold text-dark mb-0", + children: user.full_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: ["@", user.username] + })] + })] + }), /*#__PURE__*/_jsx("span", { + className: `badge bg-${roleColor}-subtle text-${roleColor} border border-${roleColor} text-uppercase px-2 py-1`, + style: { + fontSize: '0.65rem' + }, + children: user.user_role ? user.user_role.replace(/_/g, ' ') : 'STAFF' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted mb-2.5 d-flex flex-column gap-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-1.5 text-secondary" + }), " ", user.phone || 'No phone set'] + }), user.pharmacist_reg_no ? /*#__PURE__*/_jsxs("div", { + className: "text-truncate", + title: user.pharmacist_reg_no, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-medical me-1.5 text-success" + }), " Reg: ", /*#__PURE__*/_jsx("strong", { + children: user.pharmacist_reg_no + })] + }) : null] + }), /*#__PURE__*/_jsxs("div", { + className: "p-2 bg-light rounded-2 mb-3 border", + children: [/*#__PURE__*/_jsx("div", { + className: "text-muted fw-bold mb-1", + style: { + fontSize: '0.68rem', + textTransform: 'uppercase' + }, + children: "Assigned Rights" + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-1", + children: [/*#__PURE__*/_jsx("span", { + className: `badge ${perms.admin ? 'bg-danger text-white' : 'bg-secondary-subtle text-muted text-decoration-line-through'}`, + style: { + fontSize: '0.62rem' + }, + children: "Admin" + }), /*#__PURE__*/_jsx("span", { + className: `badge ${perms.sale ? 'bg-primary text-white' : 'bg-secondary-subtle text-muted text-decoration-line-through'}`, + style: { + fontSize: '0.62rem' + }, + children: "Sale" + }), /*#__PURE__*/_jsx("span", { + className: `badge ${perms.purchase ? 'bg-success text-white' : 'bg-secondary-subtle text-muted text-decoration-line-through'}`, + style: { + fontSize: '0.62rem' + }, + children: "Purchase" + }), /*#__PURE__*/_jsx("span", { + className: `badge ${perms.sale_edit_after_1h ? 'bg-warning text-dark' : 'bg-secondary-subtle text-muted text-decoration-line-through'}`, + style: { + fontSize: '0.62rem' + }, + title: "Can edit sale bill after 1 hour", + children: "Sale Edit >1h" + }), /*#__PURE__*/_jsx("span", { + className: `badge ${perms.purchase_edit_verified ? 'bg-warning text-dark' : 'bg-secondary-subtle text-muted text-decoration-line-through'}`, + style: { + fontSize: '0.62rem' + }, + title: "Can edit verified purchase challan", + children: "Purch Edit Verif" + }), /*#__PURE__*/_jsx("span", { + className: `badge ${perms.bank_upi_audit ? 'bg-info text-dark' : 'bg-secondary-subtle text-muted text-decoration-line-through'}`, + style: { + fontSize: '0.62rem' + }, + children: "Bank Audit" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between pt-2 border-top", + children: [/*#__PURE__*/_jsx("div", { + children: isCurrent ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success px-2 py-1", + style: { + fontSize: '0.7rem' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-check-fill me-1" + }), " Active Cashier"] + }) : /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary py-0.5 px-2", + style: { + fontSize: '0.72rem' + }, + onClick: () => onSelectOperator && onSelectOperator(user), + title: "Switch active counter login to this user", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left-right me-1" + }), " Switch To"] + }) + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-outline-primary py-0.5 px-2", + style: { + fontSize: '0.72rem' + }, + onClick: () => openEditModal(user), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square me-1" + }), " Edit & Rights"] + })] + })] + }) + }, user.user_id); + }) + }), showEditModal && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + tabIndex: "-1", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.7)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsx("div", { + className: "modal-content shadow-lg border-0", + children: /*#__PURE__*/_jsxs("form", { + onSubmit: handleSaveStaff, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge-fill text-primary me-2" + }), editingUser ? 'Edit Staff Profile & Permissions' : 'Register New Staff Member'] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setShowEditModal(false) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Full Name ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + required: true, + value: formFullName, + onChange: e => setFormFullName(e.target.value), + placeholder: "e.g. Rahul Sharma" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Username (Login ID) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + required: true, + value: formUsername, + onChange: e => setFormUsername(e.target.value), + placeholder: "e.g. rahul_pharma" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Role" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: formRole, + onChange: e => applyRoleDefaults(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "store_manager", + children: "Store Manager (Admin)" + }), /*#__PURE__*/_jsx("option", { + value: "pharmacist", + children: "Pharmacist" + }), /*#__PURE__*/_jsx("option", { + value: "cashier", + children: "Cashier" + }), /*#__PURE__*/_jsx("option", { + value: "auditor", + children: "Auditor / Accountant" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: editingUser ? 'Reset Quick PIN (4 Digits)' : 'Quick Login PIN (4 Digits)' + }), /*#__PURE__*/_jsx("input", { + type: "password", + maxLength: "6", + className: "form-control form-control-sm", + value: formPinCode, + onChange: e => setFormPinCode(e.target.value), + placeholder: editingUser ? 'Leave blank to keep current PIN' : 'e.g. 1234' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Phone Number" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: formPhone, + onChange: e => setFormPhone(e.target.value), + placeholder: "e.g. 9876543210" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-3 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Pharmacy State Reg No" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: formRegNo, + onChange: e => setFormRegNo(e.target.value), + placeholder: "e.g. PB-PH-99214" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "ABDM Healthcare Professional Registry (HPR) ID" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + value: formHprId, + onChange: e => setFormHprId(e.target.value), + placeholder: "e.g. rahul@hpr.abdm" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card bg-light border p-3 mb-3 rounded-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold small text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check text-success me-1" + }), " Granular Access & Audit Permissions"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary", + style: { + fontSize: '0.65rem' + }, + children: "Audit Compliant" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "form-check form-switch", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "permAdmin", + checked: formPermissions.admin || false, + onChange: () => togglePermission('admin') + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small fw-semibold", + htmlFor: "permAdmin", + children: "1. Admin Control" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: "Store config & user management" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "form-check form-switch", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "permSale", + checked: formPermissions.sale || false, + onChange: () => togglePermission('sale') + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small fw-semibold", + htmlFor: "permSale", + children: "2. Sale Billing" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: "Counter POS and draft billing" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "form-check form-switch", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "permPurchase", + checked: formPermissions.purchase || false, + onChange: () => togglePermission('purchase') + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small fw-semibold", + htmlFor: "permPurchase", + children: "3. Purchase Inward" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: "Challans & stock additions" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "form-check form-switch", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "permSaleEdit", + checked: formPermissions.sale_edit_after_1h || false, + onChange: () => togglePermission('sale_edit_after_1h') + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small fw-semibold", + htmlFor: "permSaleEdit", + children: "4. Sale Edit >1 Hour" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: "Modify bills older than 60 mins" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "form-check form-switch", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "permPurchEdit", + checked: formPermissions.purchase_edit_verified || false, + onChange: () => togglePermission('purchase_edit_verified') + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small fw-semibold", + htmlFor: "permPurchEdit", + children: "5. Purch Edit Verified" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: "Edit purchase after verification" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-md-4", + children: /*#__PURE__*/_jsxs("div", { + className: "form-check form-switch", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "permBankAudit", + checked: formPermissions.bank_upi_audit || false, + onChange: () => togglePermission('bank_upi_audit') + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small fw-semibold", + htmlFor: "permBankAudit", + children: "6. Bank & UPI Audit" + }), /*#__PURE__*/_jsx("div", { + className: "text-muted", + style: { + fontSize: '0.65rem' + }, + children: "Verify statements & reconciliations" + })] + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-4", + children: [/*#__PURE__*/_jsxs("div", { + className: "form-check", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "isDefCheck", + checked: formIsDefault, + onChange: e => setFormIsDefault(e.target.checked) + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small", + htmlFor: "isDefCheck", + children: "Default Cashier on store open" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "form-check", + children: [/*#__PURE__*/_jsx("input", { + className: "form-check-input", + type: "checkbox", + id: "isActiveCheck", + checked: formIsActive, + onChange: e => setFormIsActive(e.target.checked) + }), /*#__PURE__*/_jsx("label", { + className: "form-check-label small", + htmlFor: "isActiveCheck", + children: "Account Active" + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer py-2 px-3 bg-light", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-secondary", + onClick: () => setShowEditModal(false), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "submit", + className: "btn btn-sm btn-primary fw-bold", + disabled: isSaving, + children: isSaving ? 'Saving...' : editingUser ? 'Update Staff & Permissions' : 'Save Staff Member' + })] + })] + }) + }) + }) + })] + }); +} + +// Note: Store & Statutory Licensing Setup is managed centrally in HMS -> Admin -> Medical Store. + +// ========================================================================= +// 8. STAFF & OPERATOR ROLE MANAGEMENT (END) +// ========================================================================= + +function MobileAppView({ + store, + stores, + notify, + activeOperator, + onSwitchOperator, + onExitMobile, + triggerPwaInstall +}) { + if (!store) return null; + const [mobTab, setMobTab] = useState('dashboard'); // 'dashboard', 'collector', 'auditor', 'purchase_photo' + + // Dashboard Data + const [dashData, setDashData] = useState(null); + const [loadingDash, setLoadingDash] = useState(false); + + // Rack Collector (Draft Bill) State + const [collectorItems, setCollectorItems] = useState([]); + const [itemSearchQuery, setItemSearchQuery] = useState(''); + const [searchResults, setSearchResults] = useState([]); + const [selectedItem, setSelectedItem] = useState(null); + const [selectedBatch, setSelectedBatch] = useState(null); + const [collectQty, setCollectQty] = useState(1); + const [collectUnit, setCollectUnit] = useState('Tablet'); + const [patientName, setPatientName] = useState(''); + const [patientMobile, setPatientMobile] = useState(''); + const [bedNo, setBedNo] = useState(''); + const [wardName, setWardName] = useState(''); + const [doctorName, setDoctorName] = useState(''); + const [isSavingDraft, setIsSavingDraft] = useState(false); + + // Stock Auditor State + const [auditSearch, setAuditSearch] = useState(''); + const [auditResults, setAuditResults] = useState([]); + const [auditModalItem, setAuditModalItem] = useState(null); + const [auditCount, setAuditCount] = useState(''); + const [auditReason, setAuditReason] = useState('PHYSICAL_VARIATION'); + const [auditRemarks, setAuditRemarks] = useState(''); + const [isSubmittingAudit, setIsSubmittingAudit] = useState(false); + + // Purchase Invoice Camera State + const [recentPurchases, setRecentPurchases] = useState([]); + const [selectedPurchaseId, setSelectedPurchaseId] = useState(''); + const [capturedImageBase64, setCapturedImageBase64] = useState(null); + const [isUploadingPhoto, setIsUploadingPhoto] = useState(false); + const [previewPhotoUrl, setPreviewPhotoUrl] = useState(null); + useEffect(() => { + if (store?.store_id) { + loadDashboard(); + loadRecentPurchases(); + } + }, [store?.store_id]); + const loadDashboard = async () => { + setLoadingDash(true); + try { + const res = await fetch(API_BASE + `mobile/dashboard?store_id=${store.store_id}`); + const data = await res.json(); + if (data.status) setDashData(data); + } catch (e) { + console.error("Failed to load mobile dashboard:", e); + } finally { + setLoadingDash(false); + } + }; + const loadRecentPurchases = async () => { + try { + const res = await fetch(API_BASE + `purchases?store_id=${store.store_id}&limit=15`); + const data = await res.json(); + if (data.status) { + setRecentPurchases(data.purchases || []); + if (data.purchases && data.purchases.length > 0) { + setSelectedPurchaseId(data.purchases[0].purchase_id); + } + } + } catch (e) { + console.error("Failed to load purchases:", e); + } + }; + + // Medicine Search for Collector + const handleSearchItems = async q => { + setItemSearchQuery(q); + if (q.trim().length < 2) { + setSearchResults([]); + return; + } + try { + const res = await fetch(API_BASE + `items/search?store_id=${store.store_id}&q=${encodeURIComponent(q.trim())}`); + const data = await res.json(); + if (data.status) { + setSearchResults(data.items || []); + } + } catch (e) { + console.error(e); + } + }; + const addItemToDraft = () => { + if (!selectedItem || !selectedBatch) { + notify('Please select medicine item and batch.', 'error'); + return; + } + const q = Number(collectQty); + if (q <= 0) { + notify('Quantity must be greater than 0.', 'error'); + return; + } + const upp = Number(selectedItem.units_per_pack || selectedBatch.units_per_pack || 1); + const stripMrp = Number(selectedBatch.mrp || 0); + const perUnitMrp = upp > 0 ? stripMrp / upp : stripMrp; + const totalUnits = collectUnit === 'Strip' ? q * upp : q; + const rate = collectUnit === 'Strip' ? stripMrp : perUnitMrp; + const lineGross = collectUnit === 'Strip' ? q * stripMrp : q * perUnitMrp; + const newItem = { + item_id: selectedItem.item_id, + item_name: selectedItem.item_name, + generic_name: selectedItem.generic_name || '', + unit_pack: selectedItem.unit_pack || (upp > 1 ? `Pack: ${upp} Tabs` : 'Unit'), + units_per_pack: upp, + drug_schedule: selectedItem.drug_schedule || '', + hsn_code: selectedItem.hsn_code || '3004', + gst_rate: Number(selectedBatch.gst_rate ?? selectedItem.gst_rate ?? 12.0), + batch_id: selectedBatch.batch_id, + batch_no: selectedBatch.batch_no, + expiry_display: selectedBatch.expiry_display || (selectedBatch.expiry_date ? selectedBatch.expiry_date.substring(0, 7) : ''), + expiry_date: selectedBatch.expiry_date, + current_qty: selectedBatch.current_qty || 0, + unit_mrp: stripMrp, + mrp: stripMrp, + qty: q, + sell_unit: collectUnit, + strip_qty: collectUnit === 'Strip' ? q : 0, + loose_qty: collectUnit === 'Tablet' || collectUnit === 'Unit' ? q : 0, + total_units: totalUnits, + effective_rate: Number(rate.toFixed(2)), + line_gross: Number(lineGross.toFixed(2)) + }; + setCollectorItems(prev => [...prev, newItem]); + setSelectedItem(null); + setSelectedBatch(null); + setItemSearchQuery(''); + setSearchResults([]); + setCollectQty(1); + notify(`Added ${newItem.item_name} (${newItem.qty} ${collectUnit}) to draft basket`, 'success'); + }; + const handleSaveDraft = async () => { + if (collectorItems.length === 0) { + notify('Draft basket is empty! Add items from shelves.', 'error'); + return; + } + setIsSavingDraft(true); + try { + const res = await fetch(API_BASE + 'drafts/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + patient_name: patientName.trim() || 'Walk-in Customer', + patient_mobile: patientMobile.trim(), + bed_no: bedNo.trim(), + ward_name: wardName.trim(), + doctor_name: doctorName.trim(), + collected_by_name: activeOperator ? activeOperator.full_name : 'Mobile Pharmacist', + items: collectorItems + }) + }); + const data = await res.json(); + if (data.status) { + notify(`✓ Draft Bill #${data.draft_code} saved! Cashier on counter PC can now bill it.`, 'success'); + setCollectorItems([]); + setPatientName(''); + setPatientMobile(''); + setBedNo(''); + setWardName(''); + setDoctorName(''); + } else { + notify(data.message || 'Failed to save draft bill.', 'error'); + } + } catch (e) { + notify('Network error saving draft bill: ' + e.message, 'error'); + } finally { + setIsSavingDraft(false); + } + }; + + // Auditor Search + const handleSearchAudit = async q => { + setAuditSearch(q); + if (q.trim().length < 2) { + setAuditResults([]); + return; + } + try { + const res = await fetch(API_BASE + `stock/list?store_id=${store.store_id}&limit=20&filter=all`); + const data = await res.json(); + if (data.status && data.stock) { + const filtered = data.stock.filter(s => s.item_name.toLowerCase().includes(q.toLowerCase()) || s.generic_name && s.generic_name.toLowerCase().includes(q.toLowerCase()) || s.batch_no.toLowerCase().includes(q.toLowerCase()) || s.shelf_no && s.shelf_no.toLowerCase().includes(q.toLowerCase())); + setAuditResults(filtered); + } + } catch (e) { + console.error(e); + } + }; + const handleMobileReconcile = async () => { + if (!auditModalItem) return; + const pQty = Number(auditCount); + if (isNaN(pQty) || pQty < 0) { + notify('Please enter valid physical count (>=0).', 'error'); + return; + } + setIsSubmittingAudit(true); + try { + const res = await fetch(API_BASE + 'stock/reconcile', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + store_id: store.store_id, + item_id: auditModalItem.item_id, + batch_id: auditModalItem.batch_id, + physical_qty: pQty, + audit_type: auditReason, + remarks: auditRemarks.trim() || `Mobile Shelf Audit by ${activeOperator?.full_name || 'Staff'}`, + operator_id: activeOperator?.user_id || 1, + operator_name: activeOperator?.full_name || 'Mobile Auditor' + }) + }); + const data = await res.json(); + if (data.status) { + notify(`Reconciled ${auditModalItem.item_name}! System ${auditModalItem.current_qty} -> Shelf ${pQty}`, 'success'); + setAuditModalItem(null); + handleSearchAudit(auditSearch); + } else { + notify(data.message || 'Failed to reconcile.', 'error'); + } + } catch (e) { + notify('Network error.', 'error'); + } finally { + setIsSubmittingAudit(false); + } + }; + + // Purchase Invoice Photo Capture + const handleCaptureFile = e => { + const file = e.target.files && e.target.files[0]; + if (file) { + const reader = new FileReader(); + reader.onload = evt => { + setCapturedImageBase64(evt.target.result); + }; + reader.readAsDataURL(file); + } + }; + const handleUploadPhoto = async () => { + if (!selectedPurchaseId || !capturedImageBase64) { + notify('Please select an inward purchase and take/select a photo.', 'error'); + return; + } + setIsUploadingPhoto(true); + try { + const res = await fetch(API_BASE + 'purchase/upload-photo', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + purchase_id: Number(selectedPurchaseId), + image_data: capturedImageBase64 + }) + }); + const data = await res.json(); + if (data.status) { + notify('Purchase paper invoice photo attached successfully!', 'success'); + setCapturedImageBase64(null); + loadRecentPurchases(); + } else { + notify(data.message || 'Failed to attach photo.', 'error'); + } + } catch (e) { + notify('Network error uploading photo: ' + e.message, 'error'); + } finally { + setIsUploadingPhoto(false); + } + }; + return /*#__PURE__*/_jsxs("div", { + className: "mobile-app-wrapper", + style: { + background: '#0b1329', + minHeight: '100vh', + color: '#f8fafc', + paddingBottom: '75px' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "p-3 border-bottom border-slate-800 d-flex align-items-center justify-content-between sticky-top", + style: { + background: '#0f172a', + zIndex: 1020 + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "p-2 rounded-3 bg-primary text-white d-flex align-items-center justify-content-center", + style: { + width: 34, + height: 34 + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-capsule fs-6" + }) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold text-white fs-6 lh-1", + children: store.store_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-cyan-400", + style: { + fontSize: '0.68rem', + color: '#38bdf8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-fill me-0.5" + }), " ", activeOperator ? activeOperator.full_name : 'Staff'] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-1.5", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-info text-white rounded-pill px-2 py-1", + onClick: onSwitchOperator, + title: "Switch Operator", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge" + }), " PIN"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-success rounded-pill px-2 py-1", + onClick: triggerPwaInstall, + title: "Install PWA on Phone", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone" + }), " Install"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-secondary text-white rounded-pill px-2 py-1", + onClick: onExitMobile, + title: "Switch to Desktop Mode", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-laptop" + }), " Desktop"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "p-3", + children: [mobTab === 'dashboard' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0 text-white d-flex align-items-center gap-1.5", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-speedometer2 text-primary" + }), " Pharmacy Health Dashboard"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-xs btn-outline-secondary text-white", + onClick: loadDashboard, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }), " Refresh"] + })] + }), loadingDash || !dashData ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-5 text-slate-400", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border spinner-border-sm text-primary mb-2" + }), /*#__PURE__*/_jsx("div", { + children: "Loading store telemetry..." + })] + }) : /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-secondary", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-slate-400 d-block", + style: { + fontSize: '0.68rem', + color: '#94a3b8' + }, + children: "TOTAL BATCHES" + }), /*#__PURE__*/_jsx("span", { + className: "fs-5 fw-bolder text-white", + children: dashData.summary?.total_batches || 0 + }), /*#__PURE__*/_jsxs("span", { + className: "small text-slate-400 ms-1", + style: { + fontSize: '0.68rem' + }, + children: ["(", dashData.summary?.total_units || 0, " Units)"] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-primary", + style: { + background: 'rgba(14, 165, 233, 0.15)' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-cyan-300 d-block", + style: { + fontSize: '0.68rem', + color: '#38bdf8' + }, + children: "STOCK VALUATION (PTR)" + }), /*#__PURE__*/_jsxs("span", { + className: "fs-5 fw-bolder text-white", + children: ["₹", Number(dashData.summary?.cost_valuation || 0).toLocaleString('en-IN')] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-warning", + style: { + background: 'rgba(234, 179, 8, 0.12)' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-warning d-block", + style: { + fontSize: '0.68rem' + }, + children: "NEAR EXPIRY (<90d)" + }), /*#__PURE__*/_jsxs("span", { + className: "fs-5 fw-bolder text-warning", + children: [dashData.summary?.near_expiry_count || 0, " Batches"] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2.5 rounded-3 border border-danger", + style: { + background: 'rgba(239, 68, 68, 0.12)' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-danger d-block", + style: { + fontSize: '0.68rem' + }, + children: "SUPPLIER PENDING" + }), /*#__PURE__*/_jsxs("span", { + className: "fs-5 fw-bolder text-danger", + children: ["₹", Number(dashData.summary?.total_supplier_pending || 0).toLocaleString('en-IN')] + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 mb-3 rounded-3 overflow-hidden", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header border-bottom border-secondary py-2 px-3 d-flex align-items-center justify-content-between", + children: [/*#__PURE__*/_jsxs("span", { + className: "small fw-bold text-warning d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history" + }), " Nearest Expiry Batches"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-warning text-dark", + style: { + fontSize: '0.65rem' + }, + children: "Priority Action" + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-0", + children: dashData.near_expiry?.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "p-3 text-center small text-slate-400", + children: "No batches expiring in next 90 days." + }) : dashData.near_expiry.map((item, i) => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 border-bottom border-slate-700 d-flex align-items-center justify-content-between small", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white", + children: item.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem', + color: '#94a3b8' + }, + children: ["Batch: ", /*#__PURE__*/_jsx("strong", { + className: "text-cyan-300", + children: item.batch_no + }), " ", item.shelf_no ? `• Sh: ${item.shelf_no}` : ''] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger mb-0.5", + style: { + fontSize: '0.68rem' + }, + children: ["Exp: ", item.expiry_date] + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem' + }, + children: [item.current_qty, " Units"] + })] + })] + }, i)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 mb-3 rounded-3 overflow-hidden", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header border-bottom border-secondary py-2 px-3 d-flex align-items-center justify-content-between", + children: [/*#__PURE__*/_jsxs("span", { + className: "small fw-bold text-success d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-graph-up-arrow" + }), " Fast Moving Medicines"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-success-subtle text-success", + style: { + fontSize: '0.65rem' + }, + children: "Top Sales" + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-0", + children: dashData.high_sales?.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "p-3 text-center small text-slate-400", + children: "No sale records yet." + }) : dashData.high_sales.map((item, i) => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 border-bottom border-slate-700 d-flex align-items-center justify-content-between small", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "fw-bold text-white", + children: ["#", i + 1, " ", item.item_name] + }), /*#__PURE__*/_jsx("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem', + color: '#94a3b8' + }, + children: item.generic_name || 'Allopathic' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-success", + style: { + fontSize: '0.7rem' + }, + children: [item.total_sold, " Units Sold"] + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem' + }, + children: ["₹", item.total_revenue] + })] + })] + }, i)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 mb-3 rounded-3 overflow-hidden", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header border-bottom border-secondary py-2 px-3 d-flex align-items-center justify-content-between", + children: [/*#__PURE__*/_jsxs("span", { + className: "small fw-bold text-danger d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle-fill" + }), " Dead / Dump Stock (>60d No Movement)"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-danger-subtle text-danger", + style: { + fontSize: '0.65rem' + }, + children: "Capital Blocked" + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-0", + children: dashData.dump_stock?.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "p-3 text-center small text-slate-400", + children: "No stagnant stock detected." + }) : dashData.dump_stock.map((item, i) => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 border-bottom border-slate-700 d-flex align-items-center justify-content-between small", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white", + children: item.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem', + color: '#94a3b8' + }, + children: ["Batch: ", item.batch_no, " • Exp: ", item.expiry_date] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary", + style: { + fontSize: '0.7rem' + }, + children: [item.current_qty, " Units Stagnant"] + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem' + }, + children: ["MRP: ₹", item.mrp] + })] + })] + }, i)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 mb-3 rounded-3 overflow-hidden", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header border-bottom border-secondary py-2 px-3 d-flex align-items-center justify-content-between", + children: [/*#__PURE__*/_jsxs("span", { + className: "small fw-bold text-info d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-wallet2" + }), " Supplier Payments Pending"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-info-subtle text-info", + style: { + fontSize: '0.65rem' + }, + children: "Accounts Payable" + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-0", + children: dashData.supplier_pending?.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "p-3 text-center small text-slate-400", + children: "All supplier bills are settled!" + }) : dashData.supplier_pending.map((item, i) => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 border-bottom border-slate-700 d-flex align-items-center justify-content-between small", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white", + children: item.supplier_name || 'Distributor' + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem', + color: '#94a3b8' + }, + children: ["Inv: ", item.supplier_invoice_no, " • Due: ", item.due_date] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "text-end", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-danger", + children: ["₹", Number(item.pending_amount).toFixed(2)] + }), /*#__PURE__*/_jsxs("small", { + className: "text-slate-400 d-block", + style: { + fontSize: '0.65rem' + }, + children: ["Paid: ₹", item.paid_amount] + })] + })] + }, i)) + })] + })] + })] + }), mobTab === 'collector' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-2", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0 text-white d-flex align-items-center gap-1.5", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-basket-fill text-warning" + }), " Shelf & Rack Collector"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning text-dark small fw-bold", + children: [collectorItems.length, " Items in Basket"] + })] + }), /*#__PURE__*/_jsx("p", { + className: "text-slate-400 small mb-3", + style: { + fontSize: '0.75rem', + color: '#94a3b8' + }, + children: "Collect medicines from shelves, add to mobile basket, and tap \"Save Draft\" so the cashier on counter PC can bill it immediately." + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold text-slate-300 mb-1", + children: "Search Medicine to Pick" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-dark border-secondary text-slate-400", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Type medicine name / barcode...", + value: itemSearchQuery, + onChange: e => handleSearchItems(e.target.value) + })] + }), searchResults.length > 0 && /*#__PURE__*/_jsx("div", { + className: "rounded-3 border border-secondary mt-1 p-1 shadow-lg", + style: { + background: '#1e293b', + maxHeight: 200, + overflowY: 'auto' + }, + children: searchResults.map(item => /*#__PURE__*/_jsxs("div", { + className: "p-2 border-bottom border-slate-700 cursor-pointer text-start hover-bg", + onClick: () => { + setSelectedItem(item); + setSelectedBatch(item.batches && item.batches[0] ? item.batches[0] : null); + setSearchResults([]); + }, + style: { + cursor: 'pointer' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white small", + children: item.item_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-slate-400", + style: { + fontSize: '0.7rem', + color: '#94a3b8' + }, + children: [item.generic_name, " • Stock: ", /*#__PURE__*/_jsx("strong", { + className: "text-success", + children: item.total_stock + }), " Units"] + })] + }, item.item_id)) + })] + }), selectedItem && /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 mb-3 border border-primary", + style: { + background: 'rgba(14, 165, 233, 0.12)' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white fs-6 mb-1", + children: selectedItem.item_name + }), /*#__PURE__*/_jsx("small", { + className: "text-slate-400 d-block mb-2", + children: selectedItem.generic_name + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small mb-1", + children: "Select Batch from Shelf" + }), /*#__PURE__*/_jsx("select", { + className: "form-select form-select-sm bg-dark text-white border-secondary", + value: selectedBatch?.batch_id || '', + onChange: e => { + const b = selectedItem.batches?.find(bt => bt.batch_id == e.target.value); + setSelectedBatch(b || null); + }, + children: (selectedItem.batches || []).map(b => /*#__PURE__*/_jsxs("option", { + value: b.batch_id, + children: ["Batch: ", b.batch_no, " | Exp: ", b.expiry_date, " | Stock: ", b.current_qty, " | Sh: ", b.shelf_no || '-'] + }, b.batch_id)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small mb-1", + children: "Sell Unit" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm bg-dark text-white border-secondary", + value: collectUnit, + onChange: e => setCollectUnit(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "Tablet", + children: "Tablet / Loose" + }), /*#__PURE__*/_jsx("option", { + value: "Strip", + children: "Strip / Full Pack" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small mb-1", + children: "Quantity" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary text-white", + type: "button", + onClick: () => setCollectQty(Math.max(1, collectQty - 1)), + children: "-" + }), /*#__PURE__*/_jsx("input", { + type: "number", + min: "1", + className: "form-control text-center fw-bold bg-dark text-white border-secondary", + value: collectQty, + onChange: e => setCollectQty(Math.max(1, Number(e.target.value))) + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary text-white", + type: "button", + onClick: () => setCollectQty(collectQty + 1), + children: "+" + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between pt-2", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-secondary text-white", + onClick: () => setSelectedItem(null), + children: "Cancel" + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-primary fw-bold", + onClick: addItemToDraft, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle me-1" + }), " Add to Basket"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 rounded-3 mb-3", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header border-bottom border-secondary py-2 px-3 d-flex align-items-center justify-content-between", + children: [/*#__PURE__*/_jsxs("span", { + className: "small fw-bold text-white", + children: ["Draft Basket Items (", collectorItems.length, ")"] + }), collectorItems.length > 0 && /*#__PURE__*/_jsx("button", { + className: "btn btn-xs btn-outline-danger", + onClick: () => setCollectorItems([]), + children: "Clear" + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-0", + children: collectorItems.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "p-4 text-center text-slate-400 small", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cart3 fs-3 d-block mb-1 text-slate-600" + }), "No medicines collected yet. Search and pick items above."] + }) : collectorItems.map((it, idx) => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 border-bottom border-slate-700 d-flex align-items-center justify-content-between small", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white", + children: it.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem' + }, + children: ["Batch: ", it.batch_no, " • Qty: ", /*#__PURE__*/_jsxs("strong", { + className: "text-cyan-300", + children: [it.qty, " ", it.sell_unit] + }), " • Rate: ", /*#__PURE__*/_jsxs("strong", { + className: "text-warning", + children: ["₹", it.effective_rate] + }), " • Total: ", /*#__PURE__*/_jsxs("strong", { + className: "text-success", + children: ["₹", it.line_gross] + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-xs btn-outline-danger p-1", + onClick: () => setCollectorItems(collectorItems.filter((_, i) => i !== idx)), + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-trash" + }) + })] + }, idx)) + })] + }), collectorItems.length > 0 && /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 mb-3 border border-secondary", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold text-uppercase mb-2", + style: { + color: '#cbd5e1' + }, + children: "Patient / Counter Destination" + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Patient Name / Walk-in", + value: patientName, + onChange: e => setPatientName(e.target.value) + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Mobile Number", + value: patientMobile, + onChange: e => setPatientMobile(e.target.value) + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Bed / Room No (optional)", + value: bedNo, + onChange: e => setBedNo(e.target.value) + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Ward Name", + value: wardName, + onChange: e => setWardName(e.target.value) + }) + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-primary w-100 py-2 fw-bold d-flex align-items-center justify-content-center gap-2 shadow", + onClick: handleSaveDraft, + disabled: isSavingDraft, + children: isSavingDraft ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm" + }), " Transmitting to Counter Desk..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-send-check-fill" + }), " Save Draft to Counter Desk"] + }) + })] + })] + }), mobTab === 'auditor' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-2", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0 text-white d-flex align-items-center gap-1.5", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-sliders2 text-info" + }), " Mobile Shelf Auditor"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-info-subtle text-info border border-info", + style: { + fontSize: '0.65rem' + }, + children: "Routine Count" + })] + }), /*#__PURE__*/_jsx("p", { + className: "text-slate-400 small mb-3", + style: { + fontSize: '0.75rem', + color: '#94a3b8' + }, + children: "During low workload hours, search medicine or rack, check shelf count against system records, and reconcile stock with 1 tap." + }), /*#__PURE__*/_jsxs("div", { + className: "input-group mb-3", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-dark border-secondary text-slate-400", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Search medicine, batch, shelf no...", + value: auditSearch, + onChange: e => handleSearchAudit(e.target.value) + })] + }), /*#__PURE__*/_jsx("div", { + className: "d-flex flex-column gap-2", + children: auditResults.length === 0 ? /*#__PURE__*/_jsx("div", { + className: "text-center py-4 text-slate-500 small", + children: "Type medicine or batch to verify shelf stock." + }) : auditResults.map((item, idx) => /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 border border-secondary", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-start justify-content-between gap-2 mb-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white small", + children: item.item_name + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.72rem', + color: '#94a3b8' + }, + children: ["Batch: ", /*#__PURE__*/_jsx("strong", { + className: "text-cyan-300", + children: item.batch_no + }), " • Exp: ", item.expiry_display || item.expiry_date] + })] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary", + style: { + fontSize: '0.65rem' + }, + children: item.shelf_no ? `Shelf: ${item.shelf_no}` : 'Normal' + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between pt-2 border-top border-slate-700 mt-2", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("small", { + className: "text-slate-400 d-block", + style: { + fontSize: '0.65rem' + }, + children: "SYSTEM STOCK" + }), /*#__PURE__*/_jsxs("span", { + className: "fs-6 fw-bold text-success", + children: [item.current_qty, " Units"] + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-xs btn-outline-info text-white px-2.5 py-1 rounded-pill d-flex align-items-center gap-1", + onClick: () => { + setAuditModalItem(item); + setAuditCount(item.current_qty); + setAuditReason('PHYSICAL_VARIATION'); + setAuditRemarks(''); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-pencil-square" + }), " Count & Reconcile"] + })] + })] + }, idx)) + }), auditModalItem && /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.85)', + zIndex: 10700 + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-2xl rounded-4 overflow-hidden", + style: { + background: '#0f172a', + color: '#f8fafc', + border: '1px solid #334155' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header border-bottom border-secondary py-2.5 px-3", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold text-white mb-0 small", + children: ["Reconcile: ", auditModalItem.item_name] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: () => setAuditModalItem(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2 rounded-3 border border-secondary text-center", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-slate-400 d-block", + style: { + fontSize: '0.65rem' + }, + children: "System Qty" + }), /*#__PURE__*/_jsx("span", { + className: "fs-4 fw-bolder text-white", + children: auditModalItem.current_qty + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-6", + children: /*#__PURE__*/_jsxs("div", { + className: "p-2 rounded-3 border border-primary text-center", + style: { + background: 'rgba(14, 165, 233, 0.15)' + }, + children: [/*#__PURE__*/_jsx("small", { + className: "text-cyan-300 d-block", + style: { + fontSize: '0.65rem' + }, + children: "Physical Count" + }), /*#__PURE__*/_jsx("input", { + type: "number", + min: "0", + className: "form-control form-control-sm text-center fw-bolder text-cyan-300 bg-dark border-primary", + value: auditCount, + onChange: e => setAuditCount(e.target.value), + autoFocus: true + })] + }) + })] + }), (() => { + const sys = Number(auditModalItem.current_qty); + const phy = Number(auditCount !== '' ? auditCount : sys); + const diff = phy - sys; + const rate = Number(auditModalItem.ptr || auditModalItem.mrp || 0); + const val = Math.abs(diff) * rate; + if (diff === 0) { + return /*#__PURE__*/_jsx("div", { + className: "alert alert-success py-1.5 px-2 small mb-2", + children: "✓ Counts match (0 diff)." + }); + } else if (diff < 0) { + return /*#__PURE__*/_jsxs("div", { + className: "alert alert-danger py-1.5 px-2 small mb-2", + children: [/*#__PURE__*/_jsxs("strong", { + children: ["Shortage: ", Math.abs(diff), " units"] + }), " (Loss: ₹", val.toFixed(2), ")"] + }); + } else { + return /*#__PURE__*/_jsxs("div", { + className: "alert alert-info py-1.5 px-2 small mb-2", + children: [/*#__PURE__*/_jsxs("strong", { + children: ["Surplus: +", diff, " units"] + }), " (Valuation: ₹", val.toFixed(2), ")"] + }); + } + })(), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small mb-1", + children: "Reason" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm bg-dark text-white border-secondary", + value: auditReason, + onChange: e => setAuditReason(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "PHYSICAL_VARIATION", + children: "Physical Shelf Miscount" + }), /*#__PURE__*/_jsx("option", { + value: "DAMAGE", + children: "Damaged Foil / Bottle" + }), /*#__PURE__*/_jsx("option", { + value: "BREAKAGE", + children: "Breakage / Leakage" + }), /*#__PURE__*/_jsx("option", { + value: "EXPIRY_DUMP", + children: "Expired Stock Disposed" + }), /*#__PURE__*/_jsx("option", { + value: "SURPLUS_FOUND", + children: "Surplus Found" + }), /*#__PURE__*/_jsx("option", { + value: "THEFT_LOSS", + children: "Unaccounted Shortage" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-2", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small mb-1", + children: "Remarks" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm bg-dark text-white border-secondary", + placeholder: "Shelf location / note", + value: auditRemarks, + onChange: e => setAuditRemarks(e.target.value) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer border-top border-secondary py-2 px-3", + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-xs btn-outline-secondary", + onClick: () => setAuditModalItem(null), + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-primary fw-bold", + onClick: handleMobileReconcile, + disabled: isSubmittingAudit, + children: isSubmittingAudit ? 'Saving...' : 'Commit Adjustment' + })] + })] + }) + }) + })] + }), mobTab === 'purchase_photo' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-2", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-0 text-white d-flex align-items-center gap-1.5", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera-fill text-primary" + }), " Inward Bill Camera Attachment"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-primary-subtle text-primary border border-primary", + style: { + fontSize: '0.65rem' + }, + children: "Audit Proof" + })] + }), /*#__PURE__*/_jsx("p", { + className: "text-slate-400 small mb-3", + style: { + fontSize: '0.75rem', + color: '#94a3b8' + }, + children: "Take a direct photo of the distributor's delivery challan or paper tax invoice and attach it to the inward record." + }), /*#__PURE__*/_jsxs("div", { + className: "p-3 rounded-3 mb-3 border border-secondary", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold text-uppercase mb-1", + style: { + color: '#cbd5e1' + }, + children: "1. Select Inward Purchase Bill" + }), /*#__PURE__*/_jsx("select", { + className: "form-select form-select-sm bg-dark text-white border-secondary mb-3", + value: selectedPurchaseId, + onChange: e => setSelectedPurchaseId(e.target.value), + children: recentPurchases.map(p => /*#__PURE__*/_jsxs("option", { + value: p.purchase_id, + children: ["#", p.purchase_id, " | Inv: ", p.supplier_invoice_no, " | ", p.supplier_name || 'Distributor', " (₹", p.net_amount, ")"] + }, p.purchase_id)) + }), /*#__PURE__*/_jsx("label", { + className: "form-label text-slate-300 small fw-bold text-uppercase mb-1", + style: { + color: '#cbd5e1' + }, + children: "2. Take Paper Invoice Photo" + }), /*#__PURE__*/_jsx("div", { + className: "mb-3", + children: /*#__PURE__*/_jsxs("label", { + className: "btn btn-outline-primary btn-sm w-100 py-3 d-flex flex-column align-items-center justify-content-center gap-1.5 rounded-3", + style: { + borderStyle: 'dashed', + borderWidth: '2px', + cursor: 'pointer' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera fs-3" + }), /*#__PURE__*/_jsx("span", { + className: "fw-bold small", + children: "Snap Photo with Phone Camera" + }), /*#__PURE__*/_jsx("small", { + className: "text-slate-400", + style: { + fontSize: '0.68rem' + }, + children: "or choose from device gallery" + }), /*#__PURE__*/_jsx("input", { + type: "file", + accept: "image/*", + capture: "environment", + className: "d-none", + onChange: handleCaptureFile + })] + }) + }), capturedImageBase64 && /*#__PURE__*/_jsxs("div", { + className: "mb-3 text-center", + children: [/*#__PURE__*/_jsx("div", { + className: "small text-slate-400 mb-1 text-start", + children: "Preview of Captured Bill:" + }), /*#__PURE__*/_jsx("img", { + src: capturedImageBase64, + alt: "Captured Invoice", + className: "rounded-3 border border-secondary shadow-sm", + style: { + maxWidth: '100%', + maxHeight: 220, + objectFit: 'contain', + background: '#000' + } + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-primary w-100 py-2 fw-bold d-flex align-items-center justify-content-center gap-2 shadow", + onClick: handleUploadPhoto, + disabled: isUploadingPhoto || !capturedImageBase64, + children: isUploadingPhoto ? /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm" + }), " Attaching Image..."] + }) : /*#__PURE__*/_jsxs(_Fragment, { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cloud-arrow-up-fill" + }), " Upload & Attach to Purchase"] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card border-0 rounded-3", + style: { + background: '#1e293b' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "card-header border-bottom border-secondary py-2 px-3", + children: /*#__PURE__*/_jsx("span", { + className: "small fw-bold text-white", + children: "Recent Purchases with Photo Status" + }) + }), /*#__PURE__*/_jsx("div", { + className: "p-0", + children: recentPurchases.slice(0, 5).map(p => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 border-bottom border-slate-700 d-flex align-items-center justify-content-between small", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-white", + children: p.supplier_invoice_no + }), /*#__PURE__*/_jsxs("div", { + className: "text-slate-400", + style: { + fontSize: '0.7rem' + }, + children: [p.supplier_name || 'Distributor', " • ₹", p.net_amount] + })] + }), /*#__PURE__*/_jsx("div", { + children: p.invoice_photo ? /*#__PURE__*/_jsxs("a", { + href: p.invoice_photo, + target: "_blank", + rel: "noreferrer", + className: "btn btn-xs btn-outline-success d-flex align-items-center gap-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-image" + }), " View Photo"] + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary", + style: { + fontSize: '0.65rem' + }, + children: "No Photo" + }) + })] + }, p.purchase_id)) + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "fixed-bottom border-top border-slate-800 d-flex align-items-center justify-content-around py-2 px-1 shadow-lg", + style: { + background: '#0f172a', + zIndex: 1030 + }, + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-link text-decoration-none p-1 d-flex flex-column align-items-center ${mobTab === 'dashboard' ? 'text-primary fw-bold' : 'text-slate-400'}`, + onClick: () => setMobTab('dashboard'), + style: { + fontSize: '0.72rem', + color: mobTab === 'dashboard' ? '#38bdf8' : '#94a3b8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-speedometer2 fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "Dashboard" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-link text-decoration-none p-1 d-flex flex-column align-items-center position-relative ${mobTab === 'collector' ? 'text-primary fw-bold' : 'text-slate-400'}`, + onClick: () => setMobTab('collector'), + style: { + fontSize: '0.72rem', + color: mobTab === 'collector' ? '#38bdf8' : '#94a3b8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-basket-fill fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "Rack Drafts" + }), collectorItems.length > 0 && /*#__PURE__*/_jsx("span", { + className: "position-absolute top-0 start-50 translate-middle badge rounded-pill bg-danger", + style: { + fontSize: '0.6rem' + }, + children: collectorItems.length + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-link text-decoration-none p-1 d-flex flex-column align-items-center ${mobTab === 'auditor' ? 'text-primary fw-bold' : 'text-slate-400'}`, + onClick: () => setMobTab('auditor'), + style: { + fontSize: '0.72rem', + color: mobTab === 'auditor' ? '#38bdf8' : '#94a3b8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-sliders2 fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "Shelf Audit" + })] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-link text-decoration-none p-1 d-flex flex-column align-items-center ${mobTab === 'purchase_photo' ? 'text-primary fw-bold' : 'text-slate-400'}`, + onClick: () => setMobTab('purchase_photo'), + style: { + fontSize: '0.72rem', + color: mobTab === 'purchase_photo' ? '#38bdf8' : '#94a3b8' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera-fill fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "Bill Camera" + })] + })] + })] + }); +} +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(/*#__PURE__*/_jsx(ErrorBoundary, { + children: /*#__PURE__*/_jsx(App, {}) +})); \ No newline at end of file diff --git a/public/App/Nursing/index.html b/public/App/Nursing/index.html index c460e5d..e54c3a9 100644 --- a/public/App/Nursing/index.html +++ b/public/App/Nursing/index.html @@ -11,7 +11,7 @@ - + @@ -20,7 +20,6 @@ - @@ -330,2989 +329,6 @@
- + diff --git a/public/App/Nursing/nursing-app.bundle.js b/public/App/Nursing/nursing-app.bundle.js new file mode 100644 index 0000000..3324ba1 --- /dev/null +++ b/public/App/Nursing/nursing-app.bundle.js @@ -0,0 +1,4540 @@ +import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; +const { + useState, + useEffect +} = React; +const DEVICE_AUTH_KEY = 'nursing_pwa_device_auth_v1'; +const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000; +const MobileAppsModal = ({ + show, + onClose, + currentApp +}) => { + if (!show) return null; + const navigateToApp = appKey => { + if (appKey === currentApp) { + onClose(); + return; + } + if (appKey === 'doctor') { + window.location.href = '/app/doctor'; + } else if (appKey === 'nursing') { + window.location.href = '/app/nursing'; + } + }; + return /*#__PURE__*/_jsx("div", { + className: "modal fade show d-block", + style: { + backgroundColor: 'rgba(15, 23, 42, 0.7)', + zIndex: 1055, + backdropFilter: 'blur(4px)' + }, + tabIndex: "-1", + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered px-2", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content border-0 shadow-lg rounded-4 overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header text-white p-3", + style: { + background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("img", { + src: "/assets/img/logo.png", + alt: "Hospital Logo", + style: { + height: '28px', + width: 'auto', + filter: 'brightness(0) invert(1)' + }, + onError: e => { + e.target.style.display = 'none'; + } + }), /*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0 text-white", + style: { + fontSize: '15px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-grid-fill me-1 text-primary" + }), " HMS Mobile & PWA Apps Launcher"] + })] + }), /*#__PURE__*/_jsx("button", { + type: "button", + className: "btn-close btn-close-white", + onClick: onClose + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3 bg-light", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label fw-bold small text-secondary mb-2", + style: { + letterSpacing: '0.5px' + }, + children: "1. SELECT APPLICATION" + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: `card p-2 text-center h-100 ${currentApp === 'nursing' ? 'border-2 border-primary bg-primary-subtle shadow-sm' : 'border bg-white text-dark'}`, + style: { + cursor: 'pointer', + borderRadius: '12px' + }, + onClick: () => navigateToApp('nursing'), + children: [/*#__PURE__*/_jsx("div", { + className: "my-1", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill fs-3 text-primary" + }) + }), /*#__PURE__*/_jsx("div", { + className: "fw-bold small text-truncate", + style: { + fontSize: '12px' + }, + children: "Nursing Care" + }), currentApp === 'nursing' ? /*#__PURE__*/_jsx("span", { + className: "badge bg-primary mt-1", + style: { + fontSize: '9px' + }, + children: "● Active App" + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-info-subtle text-info-emphasis border border-info-subtle mt-1", + style: { + fontSize: '9px' + }, + children: "Active PWA" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: `card p-2 text-center h-100 ${currentApp === 'doctor' ? 'border-2 border-primary bg-primary-subtle shadow-sm' : 'border bg-white text-dark'}`, + style: { + cursor: 'pointer', + borderRadius: '12px' + }, + onClick: () => navigateToApp('doctor'), + children: [/*#__PURE__*/_jsx("div", { + className: "my-1", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge-fill fs-3 text-primary" + }) + }), /*#__PURE__*/_jsx("div", { + className: "fw-bold small text-truncate", + style: { + fontSize: '12px' + }, + children: "Doctor App" + }), currentApp === 'doctor' ? /*#__PURE__*/_jsx("span", { + className: "badge bg-primary mt-1", + style: { + fontSize: '9px' + }, + children: "● Active App" + }) : /*#__PURE__*/_jsx("span", { + className: "badge bg-success mt-1", + style: { + fontSize: '9px' + }, + children: "Active PWA" + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "card p-2 text-center border bg-white text-muted opacity-75 h-100", + style: { + borderRadius: '12px', + cursor: 'not-allowed' + }, + children: [/*#__PURE__*/_jsx("div", { + className: "my-1", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-capsule fs-3 text-secondary" + }) + }), /*#__PURE__*/_jsx("div", { + className: "fw-bold small text-truncate", + style: { + fontSize: '12px' + }, + children: "Pharmacy App" + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary mt-1", + style: { + fontSize: '9px' + }, + children: "Coming Soon" + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "p-3 bg-white rounded-3 border text-center shadow-sm", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-center gap-2 mb-2", + children: [/*#__PURE__*/_jsx("img", { + src: "/assets/img/logo.png", + alt: "Logo", + style: { + height: '28px' + }, + onError: e => e.target.style.display = 'none' + }), /*#__PURE__*/_jsxs("div", { + className: "text-start", + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold small text-dark", + children: "HMS Unified Mobile Portal" + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + style: { + fontSize: '10px' + }, + children: ["Domain: ", window.location.host] + })] + })] + }), /*#__PURE__*/_jsx("p", { + className: "small text-muted mb-2", + style: { + fontSize: '11px' + }, + children: "Tap any active app card above to switch between modules in your mobile app." + }), /*#__PURE__*/_jsxs("a", { + href: "/app", + className: "btn btn-outline-primary btn-sm w-100 fw-bold rounded-pill", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-house-door me-1" + }), " Open Mobile App Hub"] + })] + })] + })] + }) + }) + }); +}; +function NursingApp() { + const [showAppsModal, setShowAppsModal] = useState(false); + const [mainTab, setMainTab] = useState('ipd'); // 'ipd' or 'opd' + const [beds, setBeds] = useState([]); + const [loading, setLoading] = useState(true); + const [selectedWard, setSelectedWard] = useState('all'); + const [searchQuery, setSearchQuery] = useState(''); + const [activeBed, setActiveBed] = useState(null); + const [activeTab, setActiveTab] = useState('vitals'); + const [workspaceData, setWorkspaceData] = useState([]); + const [nurses, setNurses] = useState([]); + + // OPD Patients State + const [opdAppointments, setOpdAppointments] = useState([]); + const [opdCounts, setOpdCounts] = useState({ + all: 0, + waiting: 0, + visited: 0, + booked: 0, + cancelled: 0, + pending_vitals: 0, + done_vitals: 0 + }); + const [opdFilter, setOpdFilter] = useState('all'); + const [opdDateMode, setOpdDateMode] = useState('today'); + const [doctors, setDoctors] = useState([]); + const [selectedDoctorId, setSelectedDoctorId] = useState('0'); + const [vitalsFilter, setVitalsFilter] = useState('all'); // 'all', 'pending', 'done' + + // Modals & Action State + const [activeOpdForVitals, setActiveOpdForVitals] = useState(null); + const [opdVitalsForm, setOpdVitalsForm] = useState({ + temp: '', + pulse: '', + bp_systolic: '', + bp_diastolic: '', + spo2: '', + weight: '', + height: '', + rr_min: '' + }); + const [scanTarget, setScanTarget] = useState(null); // OPD or IPD object + const [scanType, setScanType] = useState('opd'); // 'opd' or 'ipd' + const [scanDocCategory, setScanDocCategory] = useState('Paper Document'); + const [scanImageBase64, setScanImageBase64] = useState(''); + const [scanImagePreview, setScanImagePreview] = useState(''); + + // ABDM M2 & Patient Search / Barcode Scanner State + const [showPatientSearchModal, setShowPatientSearchModal] = useState(false); + const [searchModalTab, setSearchModalTab] = useState('scan'); // 'scan' or 'type' + const [patientSearchQuery, setPatientSearchQuery] = useState(''); + const [patientSearchResults, setPatientSearchResults] = useState([]); + const [searchingPatient, setSearchingPatient] = useState(false); + const [scannerActive, setScannerActive] = useState(false); + const [scannerError, setScannerError] = useState(''); + + // ABDM M2 Wellness Vitals Modal State + const [activeWellnessPatient, setActiveWellnessPatient] = useState(null); + const [wellnessModalTab, setWellnessModalTab] = useState('vitals'); // 'vitals', 'sugar', 'activity', 'lifestyle', 'women' + const [wellnessForm, setWellnessForm] = useState({ + temperature_f: '', + pulse_rate: '', + resp_rate: '', + bp_systolic: '', + bp_diastolic: '', + spo2: '', + weight_kg: '', + height_cm: '', + pain_score: '', + waist_circumference_cm: '', + hip_circumference_cm: '', + waist_hip_ratio: '', + sugar_random: '', + sugar_fasting: '', + sugar_pp: '', + hba1c: '', + hemoglobin: '', + daily_steps: '', + sleep_hours: '', + exercise_min_per_day: '', + diet_type: '', + tobacco_status: '', + alcohol_status: '', + women_lmp: '', + women_pregnancy_status: '', + general_advice: '', + diet_lifestyle_note: '' + }); + + // ABDM M2 Health Document Modal State + const [activeDocPatient, setActiveDocPatient] = useState(null); + const [patientDocForm, setPatientDocForm] = useState({ + document_type: 'Health Document', + document_date: new Date().toISOString().slice(0, 10), + remarks: '' + }); + const [isSavingDoc, setIsSavingDoc] = useState(false); + + // Vitals History Modal State + const [wellnessHistoryPatient, setWellnessHistoryPatient] = useState(null); + const [wellnessHistoryList, setWellnessHistoryList] = useState([]); + const [loadingHistory, setLoadingHistory] = useState(false); + + // Auth & Device Security State + const PAIRED_NURSE_KEY = 'hms_nursing_paired_profile'; + const [authenticatedNurse, setAuthenticatedNurse] = useState(null); + const [pairedNurse, setPairedNurse] = useState(() => { + try { + const item = localStorage.getItem(PAIRED_NURSE_KEY); + return item ? JSON.parse(item) : null; + } catch (e) { + return null; + } + }); + const [staffIdInput, setStaffIdInput] = useState(''); + const [deviceCodeInput, setDeviceCodeInput] = useState(''); + const [pinInput, setPinInput] = useState(''); + const [pinError, setPinError] = useState(''); + const [showPairingForm, setShowPairingForm] = useState(false); + const [isVerifying, setIsVerifying] = useState(false); + const [isSettingNewPin, setIsSettingNewPin] = useState(false); + const [newPin, setNewPin] = useState(''); + const [confirmPin, setConfirmPin] = useState(''); + + // Workspace Forms (IPD) + const [vitalsForm, setVitalsForm] = useState({ + temperature_f: '', + pulse_rate: '', + resp_rate: '', + bp_systolic: '', + bp_diastolic: '', + spo2: '', + weight_kg: '', + general_note: '' + }); + const [fluidForm, setFluidForm] = useState({ + fluid_direction: 'intake', + fluid_route: 'IV (Intravenous)', + fluid_amount_ml: '', + general_note: '' + }); + const [treatmentForm, setTreatmentForm] = useState({ + treatment_text: '', + general_note: '' + }); + const [showAllDoctorOrders, setShowAllDoctorOrders] = useState(false); + const nurseFetch = async (url, options = {}) => { + const headers = Object.assign({}, options.headers || {}); + const storedPairing = localStorage.getItem(PAIRED_NURSE_KEY); + if (storedPairing) { + try { + const parsed = JSON.parse(storedPairing); + if (parsed && parsed.device_token && !headers['X-Device-Token']) { + headers['X-Device-Token'] = parsed.device_token; + } + } catch (e) {} + } + const fetchOptions = Object.assign({}, options, { + credentials: 'same-origin', + headers: headers + }); + const res = await fetch(url, fetchOptions); + if (res.status === 401) { + setAuthenticatedNurse(null); + localStorage.removeItem(DEVICE_AUTH_KEY); + } + return res; + }; + const fetchBeds = async () => { + try { + setLoading(true); + const res = await nurseFetch('/api/v1/nursing/beds'); + const json = await res.json(); + if (json.status === 1 && json.data) { + setBeds(json.data.beds || []); + } + } catch (err) { + console.error('Failed to load beds', err); + } finally { + setLoading(false); + } + }; + const fetchDoctors = async () => { + try { + const res = await nurseFetch('/api/v1/doctor/list'); + const json = await res.json(); + if (json.status === 1 && json.data) { + setDoctors(json.data); + } + } catch (err) { + console.error('Failed to load doctors', err); + } + }; + const fetchOpdAppointments = async (dateModeOverride, docIdOverride, vitalsOverride) => { + try { + const mode = dateModeOverride !== undefined ? dateModeOverride : opdDateMode; + const docId = docIdOverride !== undefined ? docIdOverride : selectedDoctorId; + const vFilter = vitalsOverride !== undefined ? vitalsOverride : vitalsFilter; + const res = await nurseFetch(`/api/v1/nursing/opd/list?date_mode=${mode}&doctor_id=${docId}&vitals_status=${vFilter}`); + const json = await res.json(); + if (json.status === 1) { + setOpdAppointments(json.appointments || []); + if (json.counts) { + setOpdCounts(json.counts); + } + } + } catch (err) { + console.error('Failed to load OPD appointments', err); + } + }; + useEffect(() => { + const savedAuth = localStorage.getItem(DEVICE_AUTH_KEY); + let hasValidAuth = false; + if (savedAuth) { + try { + const parsed = JSON.parse(savedAuth); + if (parsed && parsed.nurse && parsed.expires_at > Date.now()) { + setAuthenticatedNurse(parsed.nurse); + hasValidAuth = true; + } else { + localStorage.removeItem(DEVICE_AUTH_KEY); + } + } catch (e) {} + } + if (hasValidAuth) { + fetchBeds(); + fetchDoctors(); + fetchOpdAppointments('today', '0', 'all'); + } + }, []); + const handleVerifyPin = async () => { + const isPairing = !pairedNurse || showPairingForm; + const targetStaffId = isPairing ? staffIdInput.trim() : pairedNurse.staff_id || ''; + if (!targetStaffId) { + setPinError('Please enter your Staff ID or Username.'); + return; + } + if (isPairing && (!deviceCodeInput || deviceCodeInput.trim().length < 4)) { + setPinError('Please enter the 6-digit Device Security Code from Nursing Staff Master.'); + return; + } + if (!pinInput || pinInput.length < 4) { + setPinError('Enter your 4 to 6 digit Security PIN or Password.'); + return; + } + setPinError(''); + setIsVerifying(true); + try { + const body = new URLSearchParams(); + body.append('staff_id', targetStaffId); + body.append('pin', pinInput); + if (isPairing) { + body.append('device_code', deviceCodeInput.trim()); + } else if (pairedNurse && pairedNurse.device_token) { + body.append('device_token', pairedNurse.device_token); + } + const res = await fetch('/api/v1/nursing/auth/verify-pin', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: body.toString() + }); + const json = await res.json(); + if (json.status === 1 && json.nurse) { + setAuthenticatedNurse(json.nurse); + const deviceAuthObj = { + nurse: json.nurse, + expires_at: Date.now() + THIRTY_DAYS_MS + }; + localStorage.setItem(DEVICE_AUTH_KEY, JSON.stringify(deviceAuthObj)); + const pairedObj = { + id: json.nurse.id, + staff_id: json.nurse.nurse_code || targetStaffId, + name: json.nurse.name, + device_token: json.device_token || '' + }; + localStorage.setItem(PAIRED_NURSE_KEY, JSON.stringify(pairedObj)); + setPairedNurse(pairedObj); + setShowPairingForm(false); + setPinInput(''); + setDeviceCodeInput(''); + fetchBeds(); + fetchDoctors(); + fetchOpdAppointments(opdDateMode, selectedDoctorId, vitalsFilter); + } else if (json.status === 2) { + setIsSettingNewPin(true); + } else { + if (json.need_device_code) { + setShowPairingForm(true); + } + setPinError(json.message || 'Incorrect Security PIN or Device Code.'); + } + } catch (err) { + setPinError('Connection error verifying PIN.'); + } finally { + setIsVerifying(false); + } + }; + const handleSaveNewPin = async () => { + if (!newPin || newPin.length < 4) { + setPinError('PIN must be 4 to 6 numeric digits.'); + return; + } + if (newPin !== confirmPin) { + setPinError('New PIN and Confirm PIN do not match.'); + return; + } + try { + const targetNurseId = pairedNurse ? pairedNurse.id : authenticatedNurse ? authenticatedNurse.id : 0; + const body = new URLSearchParams(); + body.append('nurse_id', targetNurseId); + body.append('staff_id', staffIdInput.trim() || (pairedNurse ? pairedNurse.staff_id : '')); + body.append('new_pin', newPin); + const res = await fetch('/api/v1/nursing/auth/set-pin', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: body.toString() + }); + const json = await res.json(); + if (json.status === 1) { + alert('Security PIN set successfully! Enter your PIN to unlock.'); + setIsSettingNewPin(false); + setNewPin(''); + setConfirmPin(''); + setPinInput(''); + } else { + setPinError(json.message || 'Failed to update PIN'); + } + } catch (err) { + setPinError('Error setting PIN.'); + } + }; + const handleLogout = () => { + setAuthenticatedNurse(null); + localStorage.removeItem(DEVICE_AUTH_KEY); + setPinInput(''); + setActiveBed(null); + }; + const handleUnpairDevice = () => { + if (confirm('Unpair this device? You will need the Staff ID and Device Security Code to pair it again.')) { + setAuthenticatedNurse(null); + setPairedNurse(null); + localStorage.removeItem(DEVICE_AUTH_KEY); + localStorage.removeItem(PAIRED_NURSE_KEY); + setShowPairingForm(true); + setPinInput(''); + setStaffIdInput(''); + setDeviceCodeInput(''); + setPinError(''); + } + }; + const openWorkspace = async bed => { + if (!bed.ipd_id || bed.status !== 'occupied') return; + setActiveBed(bed); + try { + const res = await fetch(`/api/v1/nursing/workspace/${bed.ipd_id}`); + const json = await res.json(); + if (json.status === 1) { + setWorkspaceData(json.entries || []); + } + } catch (err) { + console.error('Failed to load workspace', err); + } + }; + const handleSaveIpdEntry = async (entryType, formData) => { + if (!activeBed || !activeBed.ipd_id) return; + try { + const payload = { + entry_type: entryType, + recorded_by: authenticatedNurse ? authenticatedNurse.name : 'Staff Nurse', + recorded_by_id: authenticatedNurse ? authenticatedNurse.id : 0, + ...formData + }; + const res = await fetch(`/api/v1/nursing/entry/save/${activeBed.ipd_id}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const json = await res.json(); + if (json.status === 1) { + alert(json.message || 'Saved successfully!'); + if (entryType === 'vitals') { + setVitalsForm({ + temperature_f: '', + pulse_rate: '', + resp_rate: '', + bp_systolic: '', + bp_diastolic: '', + spo2: '', + weight_kg: '', + general_note: '' + }); + } else if (entryType === 'fluid') { + setFluidForm({ + fluid_direction: 'intake', + fluid_route: 'IV (Intravenous)', + fluid_amount_ml: '', + general_note: '' + }); + } else if (entryType === 'treatment') { + setTreatmentForm({ + treatment_text: '', + general_note: '' + }); + } + openWorkspace(activeBed); + } else { + alert(json.message || 'Failed to save entry'); + } + } catch (err) { + alert('Error saving nursing entry'); + } + }; + + // Open OPD Vitals Modal + const openOpdVitalsModal = app => { + setActiveOpdForVitals(app); + setOpdVitalsForm({ + temp: app.temp || '', + pulse: app.pulse || '', + bp_systolic: app.bp || '', + bp_diastolic: app.diastolic || '', + spo2: app.spo2 || '', + weight: app.weight || '', + height: app.height || '', + rr_min: app.rr_min || '' + }); + }; + const handleSaveOpdVitals = async () => { + if (!activeOpdForVitals) return; + try { + const payload = { + nurse_id: authenticatedNurse ? authenticatedNurse.id : 0, + nurse_name: authenticatedNurse ? authenticatedNurse.name : 'Nurse', + ...opdVitalsForm + }; + const res = await fetch(`/api/v1/nursing/opd/vitals/save/${activeOpdForVitals.opd_id}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const json = await res.json(); + if (json.status === 1) { + alert(json.message || 'OPD Patient Vitals saved successfully!'); + setActiveOpdForVitals(null); + fetchOpdAppointments(opdDateMode); + } else { + alert(json.message || 'Failed to save vitals'); + } + } catch (err) { + alert('Error saving OPD Vitals'); + } + }; + + // Open Document Scan Modal (OPD / IPD) + const openScanModal = (targetObj, targetType) => { + setScanTarget(targetObj); + setScanType(targetType); + setScanDocCategory('Paper Document'); + setScanImageBase64(''); + setScanImagePreview(''); + }; + const [cropSrc, setCropSrc] = useState(''); + const [cropper, setCropper] = useState(null); + const imageRef = React.useRef(null); + const handleScanImageCapture = e => { + const file = e.target.files[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = event => { + setCropSrc(event.target.result); + }; + reader.readAsDataURL(file); + e.target.value = ''; + }; + useEffect(() => { + if (cropSrc && imageRef.current) { + if (cropper) { + cropper.destroy(); + } + const newCropper = new Cropper(imageRef.current, { + viewMode: 1, + autoCropArea: 0.9, + responsive: true, + restore: false, + guides: true, + center: true, + highlight: true, + cropBoxMovable: true, + cropBoxResizable: true, + toggleDragModeOnDblclick: false + }); + setCropper(newCropper); + } + }, [cropSrc]); + const applyCrop = () => { + if (cropper) { + const croppedCanvas = cropper.getCroppedCanvas({ + maxWidth: 1600, + maxHeight: 1600, + imageSmoothingEnabled: true, + imageSmoothingQuality: 'high' + }); + if (croppedCanvas) { + const croppedBase64 = croppedCanvas.toDataURL('image/jpeg', 0.85); + setScanImageBase64(croppedBase64); + setScanImagePreview(croppedBase64); + } + cropper.destroy(); + setCropper(null); + setCropSrc(''); + } + }; + const cancelCrop = () => { + if (cropper) { + cropper.destroy(); + setCropper(null); + } + setCropSrc(''); + }; + const handleSaveScanDocument = async () => { + if (!scanTarget || !scanImageBase64) { + alert('Please capture or select a document photo.'); + return; + } + try { + const payload = { + nurse_id: authenticatedNurse ? authenticatedNurse.id : 0, + nurse_name: authenticatedNurse ? authenticatedNurse.name : 'Nurse', + document_type: scanDocCategory, + image_base64: scanImageBase64 + }; + const url = scanType === 'opd' ? `/api/v1/nursing/opd/scan/save/${scanTarget.opd_id}` : `/api/v1/nursing/ipd/scan/save/${scanTarget.ipd_id || scanTarget.id}`; + const res = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const json = await res.json(); + if (json.status === 1) { + alert(json.message || 'Scanned Document uploaded successfully!'); + setScanTarget(null); + if (scanType === 'opd') fetchOpdAppointments(opdDateMode); + if (scanType === 'ipd' && activeBed) openWorkspace(activeBed); + } else { + alert(json.message || 'Failed to save document scan'); + } + } catch (err) { + alert('Error saving document scan'); + } + }; + + // ----------------------------------------------------------------- + // ABDM M2 PATIENT SEARCH & BARCODE / QR SCANNER HANDLERS + // ----------------------------------------------------------------- + let scannerInstance = null; + const startBarcodeQrScanner = () => { + if (typeof Html5Qrcode === 'undefined') { + setScannerError('Scanner library is loading. Please try in a moment.'); + return; + } + setScannerError(''); + setScannerActive(true); + setTimeout(() => { + const readerElem = document.getElementById('patient-qr-reader'); + if (!readerElem) return; + try { + if (scannerInstance) { + scannerInstance.stop().catch(() => {}).finally(() => { + initHtml5QrCode(readerElem); + }); + } else { + initHtml5QrCode(readerElem); + } + } catch (e) { + setScannerError('Could not access camera: ' + (e.message || e)); + setScannerActive(false); + } + }, 300); + }; + const initHtml5QrCode = readerElem => { + try { + const html5QrCode = new Html5Qrcode("patient-qr-reader"); + scannerInstance = html5QrCode; + const config = { + fps: 12, + qrbox: { + width: 280, + height: 180 + }, + aspectRatio: 1.333334, + formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE, Html5QrcodeSupportedFormats.CODE_128, Html5QrcodeSupportedFormats.CODE_39, Html5QrcodeSupportedFormats.EAN_13, Html5QrcodeSupportedFormats.EAN_8, Html5QrcodeSupportedFormats.DATA_MATRIX] + }; + html5QrCode.start({ + facingMode: "environment" + }, config, decodedText => { + // On successful scan + stopBarcodeQrScanner(); + setSearchModalTab('type'); + setPatientSearchQuery(decodedText); + executePatientSearch(decodedText); + }, errorMessage => { + // ignore frame errors + }).catch(err => { + setScannerError('Camera permission required or camera busy: ' + (err.message || err)); + setScannerActive(false); + }); + } catch (err) { + setScannerError('Failed to initialize camera scanner: ' + (err.message || err)); + setScannerActive(false); + } + }; + const stopBarcodeQrScanner = () => { + if (scannerInstance) { + try { + scannerInstance.stop().then(() => { + scannerInstance.clear(); + scannerInstance = null; + setScannerActive(false); + }).catch(() => { + scannerInstance = null; + setScannerActive(false); + }); + } catch (e) { + scannerInstance = null; + setScannerActive(false); + } + } else { + setScannerActive(false); + } + }; + const openPatientSearch = (defaultTab = 'scan') => { + setShowPatientSearchModal(true); + setSearchModalTab(defaultTab); + setPatientSearchResults([]); + setPatientSearchQuery(''); + if (defaultTab === 'scan') { + startBarcodeQrScanner(); + } else { + stopBarcodeQrScanner(); + } + }; + const closePatientSearch = () => { + stopBarcodeQrScanner(); + setShowPatientSearchModal(false); + setPatientSearchResults([]); + setPatientSearchQuery(''); + }; + const executePatientSearch = async queryText => { + const q = queryText !== undefined ? queryText : patientSearchQuery; + if (!q || q.trim() === '') { + setPatientSearchResults([]); + return; + } + setSearchingPatient(true); + try { + const res = await fetch(`/api/v1/nursing/patient/search?q=${encodeURIComponent(q.trim())}`); + const json = await res.json(); + if (json.status === 1) { + setPatientSearchResults(json.data || []); + } else { + setPatientSearchResults([]); + } + } catch (err) { + console.error('Patient search error', err); + } finally { + setSearchingPatient(false); + } + }; + + // ABDM M2 Wellness Actions + const openWellnessModal = patient => { + setActiveWellnessPatient(patient); + setWellnessModalTab('vitals'); + const opdVitals = patient.opd_today || {}; + setWellnessForm({ + temperature_f: opdVitals.temp || '', + pulse_rate: opdVitals.pulse || '', + resp_rate: opdVitals.rr_min || '', + bp_systolic: opdVitals.bp || '', + bp_diastolic: opdVitals.diastolic || '', + spo2: opdVitals.spo2 || '', + weight_kg: opdVitals.weight || '', + height_cm: opdVitals.height || '', + pain_score: '', + waist_circumference_cm: opdVitals.waist || '', + hip_circumference_cm: '', + waist_hip_ratio: '', + sugar_random: opdVitals.glucose || '', + sugar_fasting: '', + sugar_pp: '', + hba1c: '', + hemoglobin: '', + daily_steps: '', + sleep_hours: '', + exercise_min_per_day: '', + diet_type: '', + tobacco_status: '', + alcohol_status: '', + women_lmp: '', + women_pregnancy_status: '', + general_advice: '', + diet_lifestyle_note: '' + }); + setShowPatientSearchModal(false); + stopBarcodeQrScanner(); + }; + const handleSaveWellness = async () => { + if (!activeWellnessPatient) return; + try { + const payload = { + patient_id: activeWellnessPatient.id, + recorded_by: authenticatedNurse ? authenticatedNurse.name : 'Staff Nurse', + recorded_by_id: authenticatedNurse ? authenticatedNurse.id : 0, + ...wellnessForm + }; + const res = await fetch('/api/v1/nursing/patient/wellness/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const json = await res.json(); + if (json.status === 1) { + alert('✅ ' + (json.message || 'ABDM M2 Wellness Vitals saved successfully!') + (json.bmi ? ` (BMI: ${json.bmi})` : '')); + setActiveWellnessPatient(null); + setWellnessForm({ + temperature_f: '', + pulse_rate: '', + resp_rate: '', + bp_systolic: '', + bp_diastolic: '', + spo2: '', + weight_kg: '', + height_cm: '', + pain_score: '', + waist_circumference_cm: '', + hip_circumference_cm: '', + waist_hip_ratio: '', + sugar_random: '', + sugar_fasting: '', + sugar_pp: '', + hba1c: '', + hemoglobin: '', + daily_steps: '', + sleep_hours: '', + exercise_min_per_day: '', + diet_type: '', + tobacco_status: '', + alcohol_status: '', + women_lmp: '', + women_pregnancy_status: '', + general_advice: '', + diet_lifestyle_note: '' + }); + } else { + alert(json.message || 'Failed to save wellness vitals'); + } + } catch (err) { + alert('Error saving wellness vitals'); + } + }; + + // ABDM M2 Health Document Actions + const openDocModal = patient => { + setActiveDocPatient(patient); + setScanImageBase64(''); + setScanImagePreview(''); + setPatientDocForm({ + document_type: 'Health Document', + document_date: new Date().toISOString().slice(0, 10), + remarks: '' + }); + setShowPatientSearchModal(false); + stopBarcodeQrScanner(); + }; + const handleSavePatientDocument = async () => { + if (!activeDocPatient || isSavingDoc) return; + if (!scanImageBase64) { + alert('Please capture or upload a document photo first.'); + return; + } + setIsSavingDoc(true); + try { + const payload = { + patient_id: activeDocPatient.id, + nurse_name: authenticatedNurse ? authenticatedNurse.name : 'Staff Nurse', + nurse_id: authenticatedNurse ? authenticatedNurse.id : 0, + image_base64: scanImageBase64, + ...patientDocForm + }; + const res = await fetch('/api/v1/nursing/patient/document/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const json = await res.json(); + if (json.status === 1) { + alert('✅ ' + (json.message || 'ABDM M2 Health Document uploaded successfully!')); + setActiveDocPatient(null); + setScanImageBase64(''); + setScanImagePreview(''); + } else { + alert(json.message || 'Failed to upload health document'); + } + } catch (err) { + alert('Error uploading health document'); + } finally { + setIsSavingDoc(false); + } + }; + + // Vitals History Actions + const openWellnessHistory = async patient => { + setWellnessHistoryPatient(patient); + setLoadingHistory(true); + try { + const res = await fetch(`/api/v1/nursing/patient/wellness/history/${patient.id}`); + const json = await res.json(); + if (json.status === 1) { + setWellnessHistoryList(json.records || []); + } + } catch (err) { + console.error('Failed to load history', err); + } finally { + setLoadingHistory(false); + } + }; + const getInitials = nameStr => { + if (!nameStr) return 'N'; + const parts = nameStr.trim().split(' '); + if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase(); + return nameStr.substring(0, 2).toUpperCase(); + }; + const renderNoteContent = entry => { + const text = entry.treatment_text || entry.general_note || ''; + const match = text.match(/\[IMAGE_ATTACHMENT:(.*?)\]/); + const cleanText = text.replace(/\[IMAGE_ATTACHMENT:.*?\]/, '').replace('[Doctor Note] ', ''); + return /*#__PURE__*/_jsxs("div", { + children: [cleanText && /*#__PURE__*/_jsx("div", { + className: "small fw-semibold", + children: cleanText + }), match && match[1] && /*#__PURE__*/_jsxs("div", { + className: "mt-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-primary mb-1 d-inline-flex align-items-center gap-1", + style: { + fontSize: '10px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-paperclip" + }), " Attached Document / Photo"] + }), /*#__PURE__*/_jsx("a", { + href: match[1], + target: "_blank", + rel: "noreferrer", + children: /*#__PURE__*/_jsx("img", { + src: match[1], + alt: "Attached Document", + className: "img-fluid rounded-3 border shadow-sm d-block mt-1", + style: { + maxHeight: '220px', + objectFit: 'cover' + } + }) + })] + })] + }); + }; + const displayTempF = tempC => { + if (tempC === null || tempC === undefined || tempC === '') return '-'; + const val = parseFloat(tempC) * 9 / 5 + 32; + return val.toFixed(1) + '°F'; + }; + const formatDateTime = dtStr => { + if (!dtStr) return '-'; + try { + const d = new Date(dtStr.replace(/-/g, '/')); + if (isNaN(d.getTime())) return dtStr; + return d.toLocaleDateString('en-GB', { + day: '2-digit', + month: 'short', + year: 'numeric' + }) + ' ' + d.toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit', + hour12: true + }); + } catch (e) { + return dtStr; + } + }; + + // Filtered lists: Only Admitted IPD Patients with Bed (Occupied Beds) + const filteredBeds = beds.filter(bed => { + const isOccupied = bed.status === 'occupied' || bed.patient_name && bed.patient_name.trim() !== '' || Boolean(bed.ipd_id); + const matchesWard = selectedWard === 'all' || bed.ward_name === selectedWard; + const q = searchQuery.toLowerCase(); + const matchesSearch = searchQuery === '' || (bed.bed_number || '').toLowerCase().includes(q) || (bed.patient_name || '').toLowerCase().includes(q) || (bed.uhid || '').toLowerCase().includes(q) || (bed.ipd_code || '').toLowerCase().includes(q) || (bed.doctor_name || '').toLowerCase().includes(q); + return isOccupied && matchesWard && matchesSearch; + }); + const filteredOpdAppointments = opdAppointments.filter(app => { + const matchesFilter = opdFilter === 'all' || app.status_key === opdFilter; + const q = searchQuery.toLowerCase(); + const name = (app.patient_display_name || '').toLowerCase(); + const uhid = (app.uhid || '').toLowerCase(); + const opdCode = (app.opd_code || '').toLowerCase(); + const docName = (app.doctor_name || '').toLowerCase(); + return matchesFilter && (searchQuery === '' || name.includes(q) || uhid.includes(q) || opdCode.includes(q) || docName.includes(q)); + }); + + // ------------------------------------------------------------- + // LOCK SCREEN (DEVICE REGISTRATION & PIN AUTHENTICATION) + // ------------------------------------------------------------- + if (!authenticatedNurse) { + const isQuickUnlock = Boolean(pairedNurse && !showPairingForm); + return /*#__PURE__*/_jsxs("div", { + className: "lock-screen-overlay", + children: [/*#__PURE__*/_jsx(MobileAppsModal, { + show: showAppsModal, + onClose: () => setShowAppsModal(false), + currentApp: "nursing" + }), /*#__PURE__*/_jsxs("div", { + className: "lock-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "p-4 text-center text-white position-relative", + style: { + background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)' + }, + children: [/*#__PURE__*/_jsx("button", { + type: "button", + className: "btn btn-sm btn-outline-light position-absolute top-0 end-0 m-2 rounded-circle", + style: { + width: '32px', + height: '32px', + padding: 0 + }, + onClick: () => setShowAppsModal(true), + title: "HMS Mobile & PWA Apps Launcher", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-grid-3x3-gap-fill", + style: { + fontSize: '12px' + } + }) + }), /*#__PURE__*/_jsx("img", { + src: "/assets/img/logo.png", + alt: "Hospital Logo", + className: "d-block mx-auto mb-2", + style: { + maxHeight: '40px', + filter: 'brightness(0) invert(1)' + }, + onError: e => { + e.target.style.display = 'none'; + } + }), /*#__PURE__*/_jsx("h5", { + className: "fw-bold mb-1", + children: "Nursing Care Mobile App" + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-center gap-1 opacity-75 small", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check text-success" + }), /*#__PURE__*/_jsx("span", { + children: "Hospital Intranet & Device Protected" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "p-4", + children: [pinError && /*#__PURE__*/_jsx("div", { + className: "alert alert-danger py-2 px-3 small mb-3", + children: pinError + }), !isSettingNewPin ? isQuickUnlock ? + /*#__PURE__*/ + /* ------------------------------------------------------------- + PAIRED DEVICE QUICK UNLOCK + ------------------------------------------------------------- */ + _jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "text-center mb-4", + children: [/*#__PURE__*/_jsx("div", { + className: "avatar-circle mx-auto mb-2", + style: { + width: '54px', + height: '54px', + fontSize: '18px' + }, + children: getInitials(pairedNurse.name || pairedNurse.staff_id) + }), /*#__PURE__*/_jsx("h6", { + className: "fw-bold text-dark mb-0", + children: pairedNurse.name || 'Staff Nurse' + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-dark border font-monospace mt-1", + children: pairedNurse.staff_id + }), /*#__PURE__*/_jsxs("div", { + className: "text-muted small mt-1", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-phone-fill me-1 text-primary" + }), " Trusted Hospital Device"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label fw-bold small text-muted", + children: "Enter PIN or Password to Unlock" + }), /*#__PURE__*/_jsx("input", { + type: "password", + maxLength: "20", + className: "form-control text-center fs-3 letter-spacing-2", + placeholder: "••••", + value: pinInput, + autoFocus: true, + onChange: e => setPinInput(e.target.value), + onKeyUp: e => e.key === 'Enter' && handleVerifyPin() + }), /*#__PURE__*/_jsx("small", { + className: "text-muted text-center d-block mt-1", + style: { + fontSize: '11px' + }, + children: "30-day verified session active" + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-success btn-lg w-100 py-3 fw-bold shadow-sm mb-2", + onClick: handleVerifyPin, + disabled: isVerifying, + children: isVerifying ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-2" + }), "Verifying..."] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-unlock-fill me-2" + }), " Unlock Nursing App"] + }) + }), /*#__PURE__*/_jsx("div", { + className: "text-center mt-3 pt-2 border-top", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-link btn-sm text-secondary text-decoration-none p-0", + onClick: () => { + setShowPairingForm(true); + setPinError(''); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-repeat me-1" + }), " Switch Account / Re-Pair Device"] + }) + })] + }) : + /*#__PURE__*/ + /* ------------------------------------------------------------- + FIRST-TIME DEVICE REGISTRATION / PAIRING FORM + ------------------------------------------------------------- */ + _jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "alert alert-primary py-2 px-3 small d-flex align-items-center gap-2 mb-3", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-lock-fill fs-5 text-primary" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold", + children: "First-Time Device Pairing" + }), /*#__PURE__*/_jsx("div", { + style: { + fontSize: '11px' + }, + children: "Enter Staff ID and Device Security Code from Nursing Staff Master." + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label fw-bold small text-dark mb-1", + children: ["Staff ID or Username ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control", + placeholder: "e.g. NUR-637 or username", + value: staffIdInput, + onChange: e => setStaffIdInput(e.target.value) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label fw-bold small text-dark mb-1", + children: ["Device Security Code ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-key-fill text-warning" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + maxLength: "10", + className: "form-control font-monospace fw-bold", + placeholder: "6-digit code from Admin", + value: deviceCodeInput, + onChange: e => setDeviceCodeInput(e.target.value) + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '11px' + }, + children: "Displayed on HMS Admin > Nursing Staff Master" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-4", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label fw-bold small text-dark mb-1", + children: ["App PIN or Password ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-light", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-lock-fill" + }) + }), /*#__PURE__*/_jsx("input", { + type: "password", + maxLength: "20", + className: "form-control", + placeholder: "••••", + value: pinInput, + onChange: e => setPinInput(e.target.value), + onKeyUp: e => e.key === 'Enter' && handleVerifyPin() + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-primary btn-lg w-100 py-3 fw-bold shadow-sm", + onClick: handleVerifyPin, + disabled: isVerifying, + children: isVerifying ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-2" + }), "Pairing Device..."] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-2" + }), " Register Device & Unlock"] + }) + }), pairedNurse && /*#__PURE__*/_jsx("div", { + className: "text-center mt-3 pt-2 border-top", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-link btn-sm text-secondary text-decoration-none p-0", + onClick: () => { + setShowPairingForm(false); + setPinError(''); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left me-1" + }), " Back to Quick Unlock"] + }) + })] + }) : + /*#__PURE__*/ + /* ------------------------------------------------------------- + INITIAL PIN CREATION (IF NURSE DOES NOT HAVE A PIN YET) + ------------------------------------------------------------- */ + _jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "alert alert-info py-2 small mb-3", + children: "Initial PIN Setup for Nurse Profile. Set a 4-6 digit Security PIN." + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label fw-bold small", + children: "New Security PIN" + }), /*#__PURE__*/_jsx("input", { + type: "password", + maxLength: "6", + className: "form-control text-center fs-3", + placeholder: "••••", + value: newPin, + onChange: e => setNewPin(e.target.value) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label fw-bold small", + children: "Confirm New PIN" + }), /*#__PURE__*/_jsx("input", { + type: "password", + maxLength: "6", + className: "form-control text-center fs-3", + placeholder: "••••", + value: confirmPin, + onChange: e => setConfirmPin(e.target.value) + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-primary btn-lg w-100 py-3 fw-bold shadow-sm", + onClick: handleSaveNewPin, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-2" + }), " Save PIN & Unlock"] + })] + })] + })] + })] + }); + } + + // ------------------------------------------------------------- + // UNLOCKED NURSING PWA APP + // ------------------------------------------------------------- + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx(MobileAppsModal, { + show: showAppsModal, + onClose: () => setShowAppsModal(false), + currentApp: "nursing" + }), /*#__PURE__*/_jsxs("header", { + className: "nursing-header d-flex justify-content-between align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("div", { + className: "avatar-circle", + children: getInitials(authenticatedNurse.name) + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "mb-0 fw-bold", + children: authenticatedNurse.name + }), /*#__PURE__*/_jsxs("small", { + className: "text-light opacity-75", + style: { + fontSize: '11px' + }, + children: [authenticatedNurse.designation || 'Staff Nurse', " ", /*#__PURE__*/_jsx("span", { + className: "badge bg-success ms-1", + style: { + fontSize: '9px' + }, + children: "● Active" + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-light rounded-circle p-2", + style: { + width: '36px', + height: '36px' + }, + onClick: () => setShowAppsModal(true), + title: "HMS Mobile & PWA Apps Launcher", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-grid-3x3-gap-fill" + }) + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-light rounded-circle p-2", + style: { + width: '36px', + height: '36px' + }, + onClick: () => { + fetchBeds(); + fetchOpdAppointments(opdDateMode, selectedDoctorId, vitalsFilter); + }, + title: "Refresh", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }) + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-danger rounded-circle p-2", + style: { + width: '36px', + height: '36px' + }, + onClick: handleLogout, + title: "Lock Access", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-lock-fill" + }) + })] + })] + }), /*#__PURE__*/_jsxs("main", { + className: "container-fluid py-3 px-2 px-md-3 content-with-bottom-dock", + children: [!activeBed ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "segmented-tabs mb-3", + children: [/*#__PURE__*/_jsxs("button", { + className: `segmented-tab ${mainTab === 'ipd' ? 'active' : ''}`, + onClick: () => { + setMainTab('ipd'); + fetchBeds(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital-fill me-2" + }), " Admitted IPDs (", beds.filter(b => b.status === 'occupied' || b.patient_name).length, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `segmented-tab ${mainTab === 'opd' ? 'active-blue' : ''}`, + onClick: () => { + setMainTab('opd'); + fetchOpdAppointments(opdDateMode, selectedDoctorId, vitalsFilter); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-check-fill me-2" + }), " OPD Patients (", opdAppointments.length, ")"] + })] + }), mainTab === 'ipd' ? + /*#__PURE__*/ + /* ------------------------------------------------------------- + ADMITTED IPD PATIENTS & BEDS + ------------------------------------------------------------- */ + _jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3 align-items-center", + children: [/*#__PURE__*/_jsx("div", { + className: "col-12 col-md-6", + children: /*#__PURE__*/_jsxs("div", { + className: "input-group shadow-sm rounded-pill overflow-hidden bg-white border", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white border-0 ps-3 text-secondary", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control border-0 py-2 shadow-none", + placeholder: "Search Bed No, Patient Name, UHID...", + value: searchQuery, + onChange: e => setSearchQuery(e.target.value) + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-12 col-md-6", + children: /*#__PURE__*/_jsxs("select", { + className: "form-select rounded-pill shadow-sm py-2", + value: selectedWard, + onChange: e => setSelectedWard(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "all", + children: "All Wards / Units" + }), Array.from(new Set(beds.map(b => b.ward_name))).filter(Boolean).map(w => /*#__PURE__*/_jsx("option", { + value: w, + children: w + }, w))] + }) + })] + }), /*#__PURE__*/_jsx("div", { + className: "row g-3", + children: filteredBeds.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "col-12 text-center text-muted py-5 bg-white rounded-4 border shadow-sm", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital fs-1 text-secondary opacity-50 d-block mb-2" + }), /*#__PURE__*/_jsx("h6", { + className: "fw-bold text-slate-800 mb-1", + children: "No Admitted Patients Found" + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: "There are currently no admitted IPD patients in the selected ward." + })] + }) : filteredBeds.map(bed => /*#__PURE__*/_jsx("div", { + className: "col-12 col-md-6 col-lg-4", + children: /*#__PURE__*/_jsxs("div", { + className: `bed-card p-3 bed-status-${bed.status}`, + onClick: () => openWorkspace(bed), + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start mb-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "fw-bold text-dark fs-5", + children: ["Bed ", bed.bed_number] + }), /*#__PURE__*/_jsx("span", { + className: `badge ${bed.status === 'occupied' ? 'bg-primary' : 'bg-success'} text-uppercase`, + style: { + fontSize: '9px' + }, + children: bed.status + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted d-block mb-2", + style: { + fontSize: '11px' + }, + children: bed.ward_name || 'General Ward' + }), bed.patient_name ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("div", { + className: "fw-bold text-primary text-truncate", + style: { + fontSize: '15px' + }, + children: bed.patient_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '11px' + }, + children: ["UHID: ", bed.uhid || 'N/A', " • IPD: ", bed.ipd_code || 'N/A'] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle px-2 py-1 mt-2 d-inline-block", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge me-1" + }), " ", bed.doctor_name || 'Dr. Assigned'] + })] + }) : /*#__PURE__*/_jsx("div", { + className: "text-success small fw-semibold py-2", + children: "Available for Admission" + }), /*#__PURE__*/_jsx("div", { + className: "mt-3 pt-2 border-top d-flex gap-1", + children: /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-primary w-100 py-2 fw-bold rounded-3 shadow-sm", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse me-1" + }), " Open Bedside Workspace"] + }) + })] + }) + }, bed.id)) + })] + }) : + /*#__PURE__*/ + /* ------------------------------------------------------------- + OPD PATIENTS TAB (VITALS & DOCUMENT SCANNING) + ------------------------------------------------------------- */ + _jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center justify-content-between mb-3 bg-white p-2 rounded-4 border shadow-sm flex-wrap gap-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1 bg-light p-1 rounded-pill border", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-sm rounded-pill px-3 py-1 fw-bold ${opdDateMode === 'today' ? 'btn-primary shadow-sm' : 'btn-light text-secondary'}`, + onClick: () => { + setOpdDateMode('today'); + fetchOpdAppointments('today', selectedDoctorId, vitalsFilter); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-event me-1" + }), " Today's OPDs (", opdCounts.today_total || 0, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm rounded-pill px-3 py-1 fw-bold ${opdDateMode === 'all' ? 'btn-primary shadow-sm' : 'btn-light text-secondary'}`, + onClick: () => { + setOpdDateMode('all'); + fetchOpdAppointments('all', selectedDoctorId, vitalsFilter); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar3 me-1" + }), " All Dates (", opdCounts.all_total || 0, ")"] + })] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle px-2 py-1 rounded-pill small", + style: { + fontSize: '11px' + }, + children: opdDateMode === 'today' ? '● Current Date' : '● All Appointments' + })] + }), /*#__PURE__*/_jsx("div", { + className: "bg-white p-3 mb-3 rounded-4 border shadow-sm", + children: /*#__PURE__*/_jsxs("div", { + className: "row g-2 align-items-center", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold text-dark mb-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge text-primary me-1" + }), " Filter by Doctor"] + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm rounded-pill fw-semibold", + value: selectedDoctorId, + onChange: e => { + const val = e.target.value; + setSelectedDoctorId(val); + fetchOpdAppointments(opdDateMode, val, vitalsFilter); + }, + children: [/*#__PURE__*/_jsx("option", { + value: "0", + children: "-- All Hospital Doctors --" + }), doctors.map(d => /*#__PURE__*/_jsx("option", { + value: d.id, + children: d.name + }, d.id))] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold text-dark mb-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill text-danger me-1" + }), " Vitals Status Filter"] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn btn-sm flex-fill rounded-pill py-1 fw-bold ${vitalsFilter === 'all' ? 'btn-primary shadow-sm' : 'btn-light border text-secondary'}`, + onClick: () => { + setVitalsFilter('all'); + fetchOpdAppointments(opdDateMode, selectedDoctorId, 'all'); + }, + children: ["All (", opdCounts.all, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm flex-fill rounded-pill py-1 fw-bold ${vitalsFilter === 'pending' ? 'btn-warning text-dark shadow-sm' : 'btn-light border text-secondary'}`, + onClick: () => { + setVitalsFilter('pending'); + fetchOpdAppointments(opdDateMode, selectedDoctorId, 'pending'); + }, + children: ["⚠️ Pending (", opdCounts.pending_vitals || 0, ")"] + }), /*#__PURE__*/_jsxs("button", { + className: `btn btn-sm flex-fill rounded-pill py-1 fw-bold ${vitalsFilter === 'done' ? 'btn-success text-white shadow-sm' : 'btn-light border text-secondary'}`, + onClick: () => { + setVitalsFilter('done'); + fetchOpdAppointments(opdDateMode, selectedDoctorId, 'done'); + }, + children: ["✅ Filled (", opdCounts.done_vitals || 0, ")"] + })] + })] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2 mb-3 overflow-auto no-scrollbar pb-1", + children: [/*#__PURE__*/_jsx("button", { + className: `btn btn-sm rounded-pill px-3 ${opdFilter === 'all' ? 'btn-primary fw-bold' : 'btn-white bg-white text-secondary border'}`, + onClick: () => setOpdFilter('all'), + children: "All Visits" + }), /*#__PURE__*/_jsx("button", { + className: `btn btn-sm rounded-pill px-3 ${opdFilter === 'waiting' ? 'btn-primary fw-bold' : 'btn-white bg-white text-secondary border'}`, + onClick: () => setOpdFilter('waiting'), + children: "Waiting" + }), /*#__PURE__*/_jsx("button", { + className: `btn btn-sm rounded-pill px-3 ${opdFilter === 'visited' ? 'btn-info text-dark fw-bold' : 'btn-white bg-white text-secondary border'}`, + onClick: () => setOpdFilter('visited'), + children: "Visited" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group mb-3 shadow-sm rounded-pill overflow-hidden bg-white border", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white border-0 ps-3 text-secondary", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control border-0 py-2 shadow-none", + placeholder: "Search Patient Name, Doctor Name, UHID, OPD Code...", + value: searchQuery, + onChange: e => setSearchQuery(e.target.value) + })] + }), /*#__PURE__*/_jsx("div", { + children: filteredOpdAppointments.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "text-center text-muted py-5 bg-white rounded-4 border shadow-sm", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-x fs-1 text-secondary opacity-50 d-block mb-2" + }), "No OPD appointments found for selected filter."] + }) : filteredOpdAppointments.map(app => /*#__PURE__*/_jsxs("div", { + className: "mobile-patient-card", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2 pb-2 border-bottom", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "queue-badge", + children: ["Q #", app.queue_no || app.opd_no || '1'] + }), /*#__PURE__*/_jsxs("span", { + className: `status-pill ${app.status_key}`, + children: ["● ", app.status_label] + })] + }), /*#__PURE__*/_jsx("code", { + className: "fw-bold text-dark fs-6", + children: app.opd_code + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-start gap-3 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "patient-avatar-circle", + children: getInitials(app.patient_display_name) + }), /*#__PURE__*/_jsxs("div", { + className: "flex-grow-1", + children: [/*#__PURE__*/_jsx("h5", { + className: "fw-bold text-slate-900 mb-1", + style: { + fontSize: '16px' + }, + children: app.patient_display_name + }), /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block mb-2", + style: { + fontSize: '12px' + }, + children: [app.age_display, " • ", app.gender_label, " | UHID: ", app.uhid] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle px-2 py-1", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge me-1" + }), app.doctor_name || 'Doctor'] + })] + })] + }), app.has_vitals && /*#__PURE__*/_jsxs("div", { + className: "alert alert-success py-1.5 px-3 mb-3 small rounded-3 d-flex align-items-center justify-content-between", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill text-danger me-1" + }), " ", /*#__PURE__*/_jsx("strong", { + children: "Vitals:" + }), " BP ", app.bp || '-', "/", app.diastolic || '-', " | Pulse ", app.pulse || '-', " | Temp ", app.temp || '-', "°F"] + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-success", + children: "Vitals ✓" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("button", { + className: `btn ${app.has_vitals ? 'btn-success' : 'btn-outline-success'} w-50 py-2 fw-bold rounded-3 shadow-sm`, + onClick: () => openOpdVitalsModal(app), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse me-1" + }), " ", app.has_vitals ? 'Vitals ✓' : 'Fill Vitals'] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-primary w-50 py-2 fw-bold rounded-3 shadow-sm", + onClick: () => openScanModal(app, 'opd'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera me-1" + }), " Scan / Photo"] + })] + })] + }, app.opd_id)) + })] + })] + }) : + /*#__PURE__*/ + /* ------------------------------------------------------------- + IPD BEDSIDE WORKSPACE FOR NURSING STAFF + ------------------------------------------------------------- */ + _jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-3", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-dark rounded-pill px-3", + onClick: () => setActiveBed(null), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-left me-1" + }), " Back to Bed List"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-primary fw-bold rounded-pill px-3", + onClick: () => openScanModal(activeBed, 'ipd'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera me-1" + }), " Scan Paper Doc"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "card shadow-sm mb-3 border-0 bg-primary text-white rounded-4", + style: { + background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)' + }, + children: /*#__PURE__*/_jsxs("div", { + className: "card-body p-3", + children: [/*#__PURE__*/_jsx("h5", { + className: "fw-bold mb-1", + children: activeBed.patient_name + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-2 opacity-90 small mt-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-white text-dark", + children: ["Bed ", activeBed.bed_number, " (", activeBed.ward_name, ")"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-white text-danger", + children: ["UHID: ", activeBed.uhid] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-white text-primary", + children: ["IPD: ", activeBed.ipd_code] + })] + })] + }) + }), /*#__PURE__*/_jsxs("ul", { + className: "nav nav-pills mb-3 bg-white p-1 rounded-3 border shadow-sm", + children: [/*#__PURE__*/_jsx("li", { + className: "nav-item flex-fill text-center", + children: /*#__PURE__*/_jsxs("button", { + className: `nav-link w-100 fw-bold ${activeTab === 'vitals' ? 'active' : ''}`, + onClick: () => setActiveTab('vitals'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse me-1" + }), " Vitals (", workspaceData.filter(e => e.entry_type === 'vitals').length, ")"] + }) + }), /*#__PURE__*/_jsx("li", { + className: "nav-item flex-fill text-center", + children: /*#__PURE__*/_jsxs("button", { + className: `nav-link w-100 fw-bold ${activeTab === 'fluid' ? 'active' : ''}`, + onClick: () => setActiveTab('fluid'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-droplet me-1" + }), " Fluid I/O (", workspaceData.filter(e => e.entry_type === 'fluid').length, ")"] + }) + }), /*#__PURE__*/_jsx("li", { + className: "nav-item flex-fill text-center", + children: /*#__PURE__*/_jsxs("button", { + className: `nav-link w-100 fw-bold ${activeTab === 'treatment' ? 'active' : ''}`, + onClick: () => setActiveTab('treatment'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clipboard2-pulse me-1" + }), " Treatment & Orders (", workspaceData.filter(e => e.entry_type === 'treatment').length, ")"] + }) + })] + }), activeTab === 'vitals' && /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "card p-3 shadow-sm border-0 mb-3 rounded-4", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-3 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill text-danger me-1" + }), " Record Bedside Vitals"] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "BP Sys/Dia (mmHg)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control text-center", + placeholder: "120", + value: vitalsForm.bp_systolic, + onChange: e => setVitalsForm({ + ...vitalsForm, + bp_systolic: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "/" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control text-center", + placeholder: "80", + value: vitalsForm.bp_diastolic, + onChange: e => setVitalsForm({ + ...vitalsForm, + bp_diastolic: e.target.value + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Pulse Rate (bpm)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "72", + value: vitalsForm.pulse_rate, + onChange: e => setVitalsForm({ + ...vitalsForm, + pulse_rate: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "SpO2 %" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "98", + value: vitalsForm.spo2, + onChange: e => setVitalsForm({ + ...vitalsForm, + spo2: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Temp °F" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control form-control-sm text-center", + placeholder: "98.6", + value: vitalsForm.temperature_f, + onChange: e => setVitalsForm({ + ...vitalsForm, + temperature_f: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Resp Rate (/min)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "18", + value: vitalsForm.resp_rate, + onChange: e => setVitalsForm({ + ...vitalsForm, + resp_rate: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Weight (kg)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control form-control-sm text-center", + placeholder: "70", + value: vitalsForm.weight_kg, + onChange: e => setVitalsForm({ + ...vitalsForm, + weight_kg: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Nursing Remark / Observation" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Patient resting, vitals stable", + value: vitalsForm.general_note, + onChange: e => setVitalsForm({ + ...vitalsForm, + general_note: e.target.value + }) + })] + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success fw-bold py-2 w-100 rounded-3 shadow-sm", + onClick: () => handleSaveIpdEntry('vitals', vitalsForm), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-1" + }), " Save Bedside Vitals"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card shadow-sm border-0 rounded-4 overflow-hidden mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header py-2 bg-white d-flex justify-content-between align-items-center border-bottom", + children: [/*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1 text-danger" + }), " Vitals History Records"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger-subtle", + children: [workspaceData.filter(e => e.entry_type === 'vitals').length, " Records"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-sm table-striped table-hover align-middle mb-0", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Date & Time" + }), /*#__PURE__*/_jsx("th", { + children: "BP (mmHg)" + }), /*#__PURE__*/_jsx("th", { + children: "Pulse" + }), /*#__PURE__*/_jsx("th", { + children: "Temp" + }), /*#__PURE__*/_jsx("th", { + children: "Resp" + }), /*#__PURE__*/_jsx("th", { + children: "SpO2" + }), /*#__PURE__*/_jsx("th", { + children: "Weight" + }), /*#__PURE__*/_jsx("th", { + children: "Staff" + }), /*#__PURE__*/_jsx("th", { + children: "Remarks" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: workspaceData.filter(e => e.entry_type === 'vitals').length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "9", + className: "text-center text-muted py-4", + children: "No vitals records entered yet." + }) + }) : workspaceData.filter(e => e.entry_type === 'vitals').map(v => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-semibold text-nowrap", + children: formatDateTime(v.recorded_at) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border", + children: v.bp_systolic ? `${v.bp_systolic}/${v.bp_diastolic}` : '-' + }) + }), /*#__PURE__*/_jsx("td", { + children: v.pulse_rate ? `${v.pulse_rate} bpm` : '-' + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-danger-subtle text-danger", + children: displayTempF(v.temperature_c) + }) + }), /*#__PURE__*/_jsx("td", { + children: v.resp_rate ? `${v.resp_rate}/min` : '-' + }), /*#__PURE__*/_jsx("td", { + children: v.spo2 ? `${v.spo2}%` : '-' + }), /*#__PURE__*/_jsx("td", { + children: v.weight_kg ? `${v.weight_kg} kg` : '-' + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: v.recorded_by || 'Staff' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + children: v.general_note || '-' + }) + })] + }, v.id)) + })] + }) + })] + })] + }), activeTab === 'fluid' && (() => { + const fluidList = workspaceData.filter(e => e.entry_type === 'fluid'); + const totalIn = fluidList.filter(e => (e.fluid_direction || '').toLowerCase() === 'intake').reduce((sum, e) => sum + (parseFloat(e.fluid_amount_ml) || 0), 0); + const totalOut = fluidList.filter(e => (e.fluid_direction || '').toLowerCase() === 'output').reduce((sum, e) => sum + (parseFloat(e.fluid_amount_ml) || 0), 0); + const netDiff = totalIn - totalOut; + const intakeRoutes = ['IV (Intravenous)', 'Oral / Water / Juice', 'Ryles Tube / NG Feed', 'Normal Saline (NS)', 'Dextrose (DNS / RL)', 'Blood / Plasma', 'TPN', 'Other Intake']; + const outputRoutes = ['Urine / Foley Catheter', 'Drain / Ryle Tube', 'Vomitus', 'Stool / Loose Motion', 'Chest Tube Drain', 'Wound Drain', 'Other Output']; + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "stat-card-intake text-center shadow-sm", + children: [/*#__PURE__*/_jsxs("small", { + className: "text-success fw-bold d-block mb-1", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-down-left-circle-fill me-1" + }), " Total Intake"] + }), /*#__PURE__*/_jsxs("h5", { + className: "fw-bold text-success mb-0", + children: [totalIn.toLocaleString(), " ", /*#__PURE__*/_jsx("span", { + style: { + fontSize: '11px' + }, + children: "ml" + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "stat-card-output text-center shadow-sm", + children: [/*#__PURE__*/_jsxs("small", { + className: "text-warning fw-bold d-block mb-1", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-up-right-circle-fill me-1" + }), " Total Output"] + }), /*#__PURE__*/_jsxs("h5", { + className: "fw-bold text-warning mb-0", + children: [totalOut.toLocaleString(), " ", /*#__PURE__*/_jsx("span", { + style: { + fontSize: '11px' + }, + children: "ml" + })] + })] + }) + }), /*#__PURE__*/_jsx("div", { + className: "col-4", + children: /*#__PURE__*/_jsxs("div", { + className: "stat-card-balance text-center shadow-sm", + children: [/*#__PURE__*/_jsxs("small", { + className: "text-primary fw-bold d-block mb-1", + style: { + fontSize: '11px' + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calculator me-1" + }), " Difference (In-Out)"] + }), /*#__PURE__*/_jsxs("h5", { + className: `fw-bold mb-0 ${netDiff >= 0 ? 'text-primary' : 'text-danger'}`, + children: [netDiff > 0 ? `+${netDiff.toLocaleString()}` : netDiff.toLocaleString(), " ", /*#__PURE__*/_jsx("span", { + style: { + fontSize: '11px' + }, + children: "ml" + })] + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card p-3 shadow-sm border-0 mb-3 rounded-4", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-3 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-droplet-fill text-primary me-1" + }), " Add Fluid Intake / Output Entry"] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Direction" + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm flex-fill py-2 fw-bold rounded-3 ${fluidForm.fluid_direction === 'intake' ? 'btn-success text-white shadow-sm' : 'btn-light border text-secondary'}`, + onClick: () => setFluidForm({ + ...fluidForm, + fluid_direction: 'intake', + fluid_route: 'IV (Intravenous)' + }), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-down-left-circle me-1" + }), " Fluid Intake (In)"] + }), /*#__PURE__*/_jsxs("button", { + type: "button", + className: `btn btn-sm flex-fill py-2 fw-bold rounded-3 ${fluidForm.fluid_direction === 'output' ? 'btn-warning text-dark shadow-sm' : 'btn-light border text-secondary'}`, + onClick: () => setFluidForm({ + ...fluidForm, + fluid_direction: 'output', + fluid_route: 'Urine / Foley Catheter' + }), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-up-right-circle me-1" + }), " Fluid Output (Out)"] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Route / Site" + }), /*#__PURE__*/_jsx("select", { + className: "form-select form-select-sm", + value: fluidForm.fluid_route, + onChange: e => setFluidForm({ + ...fluidForm, + fluid_route: e.target.value + }), + children: (fluidForm.fluid_direction === 'intake' ? intakeRoutes : outputRoutes).map(r => /*#__PURE__*/_jsx("option", { + value: r, + children: r + }, r)) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Amount (ml) ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center fw-bold fs-6", + placeholder: "e.g. 500", + value: fluidForm.fluid_amount_ml, + onChange: e => setFluidForm({ + ...fluidForm, + fluid_amount_ml: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Observation / Note" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Clear urine, Normal fluid color, IV site intact", + value: fluidForm.general_note, + onChange: e => setFluidForm({ + ...fluidForm, + general_note: e.target.value + }) + })] + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-primary fw-bold py-2 w-100 rounded-3 shadow-sm", + onClick: () => { + if (!fluidForm.fluid_amount_ml) { + alert('Please enter fluid amount in ml.'); + return; + } + handleSaveIpdEntry('fluid', fluidForm); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-plus-circle-fill me-1" + }), " Save Fluid Entry"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card shadow-sm border-0 rounded-4 overflow-hidden mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header py-2 bg-white d-flex justify-content-between align-items-center border-bottom", + children: [/*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1 text-primary" + }), " Fluid Intake & Output Log"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle", + children: [fluidList.length, " Records"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-sm table-striped table-hover align-middle mb-0", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Date & Time" + }), /*#__PURE__*/_jsx("th", { + children: "Direction" + }), /*#__PURE__*/_jsx("th", { + children: "Route" + }), /*#__PURE__*/_jsx("th", { + children: "Amount (ml)" + }), /*#__PURE__*/_jsx("th", { + children: "Observation / Note" + }), /*#__PURE__*/_jsx("th", { + children: "Staff" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: fluidList.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "6", + className: "text-center text-muted py-4", + children: "No fluid entries recorded yet." + }) + }) : fluidList.map(fl => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-semibold text-nowrap", + children: formatDateTime(fl.recorded_at) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: `badge ${fl.fluid_direction === 'intake' ? 'bg-success' : 'bg-warning text-dark'} text-uppercase`, + children: fl.fluid_direction === 'intake' ? '↓ Intake' : '↑ Output' + }) + }), /*#__PURE__*/_jsx("td", { + className: "fw-semibold", + children: fl.fluid_route || '-' + }), /*#__PURE__*/_jsxs("td", { + className: "fw-bold", + children: [parseFloat(fl.fluid_amount_ml || 0).toLocaleString(), " ml"] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + children: fl.general_note || '-' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: fl.recorded_by || 'Staff' + }) + })] + }, fl.id)) + })] + }) + })] + })] + }); + })(), activeTab === 'treatment' && (() => { + const allTreatments = workspaceData.filter(e => e.entry_type === 'treatment'); + const doctorOrders = allTreatments.filter(e => e.recorded_by && e.recorded_by.toLowerCase().startsWith('dr.') || e.treatment_text && e.treatment_text.includes('[Doctor Note]')); + const latestDocOrder = doctorOrders.length > 0 ? doctorOrders[0] : null; + const nurseTreatments = allTreatments.filter(e => !(e.recorded_by && e.recorded_by.toLowerCase().startsWith('dr.')) && !(e.treatment_text && e.treatment_text.includes('[Doctor Note]'))); + return /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "card shadow-sm border-0 mb-3 rounded-4 overflow-hidden", + style: { + border: '1.5px solid #818cf8' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header py-2 text-white d-flex justify-content-between align-items-center", + style: { + background: 'linear-gradient(135deg, #3730a3 0%, #4f46e5 100%)' + }, + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-medical-fill" + }), /*#__PURE__*/_jsx("strong", { + className: "small", + children: "Doctor's Prescribed Treatment & Orders" + })] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-white text-dark small", + children: [doctorOrders.length, " Doctor Orders"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "card-body p-3 bg-light", + children: latestDocOrder ? /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start mb-2", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-primary px-2 py-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge me-1" + }), " ", latestDocOrder.recorded_by] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted fw-semibold", + children: formatDateTime(latestDocOrder.recorded_at) + })] + }), /*#__PURE__*/_jsx("div", { + className: "p-3 bg-white rounded-3 border mb-2 shadow-sm", + children: renderNoteContent(latestDocOrder) + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-primary fw-bold w-100 rounded-pill py-2", + onClick: () => { + const cleanText = (latestDocOrder.treatment_text || '').replace(/\[IMAGE_ATTACHMENT:.*?\]/, '').replace('[Doctor Note] ', '').trim(); + setTreatmentForm({ + ...treatmentForm, + treatment_text: `Administered as prescribed: ${cleanText}` + }); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clipboard-check-fill me-1" + }), " Follow & Administer This Order"] + }), doctorOrders.length > 1 && /*#__PURE__*/_jsxs("div", { + className: "mt-3", + children: [/*#__PURE__*/_jsxs("button", { + type: "button", + className: "btn btn-sm btn-light border w-100 text-secondary", + onClick: () => setShowAllDoctorOrders(!showAllDoctorOrders), + children: [/*#__PURE__*/_jsx("i", { + className: `bi bi-chevron-${showAllDoctorOrders ? 'up' : 'down'} me-1` + }), showAllDoctorOrders ? 'Hide Previous Doctor Notes' : `View All ${doctorOrders.length} Doctor Notes`] + }), showAllDoctorOrders && /*#__PURE__*/_jsx("div", { + className: "mt-2 d-flex flex-column gap-2", + children: doctorOrders.slice(1).map(docOrd => /*#__PURE__*/_jsxs("div", { + className: "p-2.5 bg-white rounded-3 border", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-1", + children: [/*#__PURE__*/_jsx("strong", { + className: "text-primary small", + children: docOrd.recorded_by + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '11px' + }, + children: formatDateTime(docOrd.recorded_at) + })] + }), renderNoteContent(docOrd)] + }, docOrd.id)) + })] + })] + }) : /*#__PURE__*/_jsxs("div", { + className: "text-center text-muted py-3", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clipboard-x fs-2 text-secondary opacity-50 d-block mb-1" + }), /*#__PURE__*/_jsx("small", { + children: "No doctor orders or clinical prescriptions recorded yet." + })] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card p-3 shadow-sm border-0 mb-3 rounded-4", + children: [/*#__PURE__*/_jsxs("h6", { + className: "fw-bold mb-3 text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-capsule text-success me-1" + }), " Log Nursing Treatment Given / Medication Administered"] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small fw-bold mb-1", + children: ["Treatment / Medication Administered ", /*#__PURE__*/_jsx("span", { + className: "text-danger", + children: "*" + })] + }), /*#__PURE__*/_jsx("textarea", { + className: "form-control rounded-3", + rows: "3", + placeholder: "e.g. Inj. Ceftriaxone 1g IV given slowly, Tab Pantop 40mg given orally...", + value: treatmentForm.treatment_text, + onChange: e => setTreatmentForm({ + ...treatmentForm, + treatment_text: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Observation / Patient Response" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Tolerated well, No adverse reaction, IV site patent", + value: treatmentForm.general_note, + onChange: e => setTreatmentForm({ + ...treatmentForm, + general_note: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success fw-bold py-2 w-100 rounded-3 shadow-sm", + onClick: () => { + if (!treatmentForm.treatment_text.trim()) { + alert('Please enter treatment or medication administered.'); + return; + } + handleSaveIpdEntry('treatment', treatmentForm); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-send-check-fill me-1" + }), " Log Treatment Administration"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "card shadow-sm border-0 rounded-4 overflow-hidden mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "card-header py-2 bg-white d-flex justify-content-between align-items-center border-bottom", + children: [/*#__PURE__*/_jsxs("strong", { + className: "text-dark", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1 text-success" + }), " Nursing Treatment Given History"] + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success-subtle", + children: [nurseTreatments.length, " Records"] + })] + }), /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-sm table-striped table-hover align-middle mb-0", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + style: { + width: '140px' + }, + children: "Time Administered" + }), /*#__PURE__*/_jsx("th", { + children: "Treatment / Medication Given" + }), /*#__PURE__*/_jsx("th", { + children: "Observation & Remarks" + }), /*#__PURE__*/_jsx("th", { + style: { + width: '120px' + }, + children: "Staff Nurse" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: nurseTreatments.length === 0 ? /*#__PURE__*/_jsx("tr", { + children: /*#__PURE__*/_jsx("td", { + colSpan: "4", + className: "text-center text-muted py-4", + children: "No nursing treatments logged yet." + }) + }) : nurseTreatments.map(tr => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-semibold text-nowrap", + children: formatDateTime(tr.recorded_at) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("div", { + className: "fw-bold text-dark", + children: renderNoteContent(tr) + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: tr.general_note || '-' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary-subtle text-secondary border", + children: tr.recorded_by || 'Staff Nurse' + }) + })] + }, tr.id)) + })] + }) + })] + })] + }); + })()] + }), activeOpdForVitals && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.5)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-success text-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill me-2" + }), " Fill OPD Patient Vitals"] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: () => setActiveOpdForVitals(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "alert alert-light border py-2 mb-3 small", + children: [/*#__PURE__*/_jsx("strong", { + children: activeOpdForVitals.patient_display_name + }), " (", activeOpdForVitals.age_display, " • ", activeOpdForVitals.gender_label, ")", /*#__PURE__*/_jsx("br", {}), /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: ["UHID: ", activeOpdForVitals.uhid, " | OPD Code: ", activeOpdForVitals.opd_code] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "BP Sys/Dia" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control text-center", + placeholder: "120", + value: opdVitalsForm.bp_systolic, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + bp_systolic: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "/" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control text-center", + placeholder: "80", + value: opdVitalsForm.bp_diastolic, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + bp_diastolic: e.target.value + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Pulse Rate (bpm)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "72", + value: opdVitalsForm.pulse, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + pulse: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "SpO2 %" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "98", + value: opdVitalsForm.spo2, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + spo2: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Temp °F" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control form-control-sm text-center", + placeholder: "98.6", + value: opdVitalsForm.temp, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + temp: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Weight (kg)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "70", + value: opdVitalsForm.weight, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + weight: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Height (cm)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "165", + value: opdVitalsForm.height, + onChange: e => setOpdVitalsForm({ + ...opdVitalsForm, + height: e.target.value + }) + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer p-2 bg-light", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-secondary btn-sm", + onClick: () => setActiveOpdForVitals(null), + children: "Cancel" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success btn-sm fw-bold px-3", + onClick: handleSaveOpdVitals, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-1" + }), " Save Vitals for Doctor"] + })] + })] + }) + }) + }), scanTarget && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.5)' + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-primary text-white", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera-fill me-2" + }), " Scan / Photo Paper Document"] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: () => setScanTarget(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "mb-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold", + children: "Document Type / Category" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: scanDocCategory, + onChange: e => setScanDocCategory(e.target.value), + children: [/*#__PURE__*/_jsx("option", { + value: "Paper Document", + children: "Paper Document (General)" + }), /*#__PURE__*/_jsx("option", { + value: "Vitals Sheet", + children: "Vitals Sheet / Chart" + }), /*#__PURE__*/_jsx("option", { + value: "Lab Test Report", + children: "Lab / Pathology Report" + }), /*#__PURE__*/_jsx("option", { + value: "Handwritten Doctor Note", + children: "Handwritten Doctor Note" + }), /*#__PURE__*/_jsx("option", { + value: "Consent Form", + children: "Signed Consent Form" + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "mb-3 text-center", + children: /*#__PURE__*/_jsxs("label", { + className: "btn btn-primary btn-lg w-100 py-3 fw-bold rounded-3 shadow-sm", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera me-2" + }), " Take Photo / Choose File", /*#__PURE__*/_jsx("input", { + type: "file", + accept: "image/*", + capture: "environment", + className: "d-none", + onChange: handleScanImageCapture + })] + }) + }), scanImagePreview && /*#__PURE__*/_jsxs("div", { + className: "position-relative p-2 border rounded-3 bg-light text-center", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-success position-absolute top-0 start-0 m-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle me-1" + }), " Document Photo Captured"] + }), /*#__PURE__*/_jsx("img", { + src: scanImagePreview, + alt: "Document Scan Preview", + className: "img-fluid rounded-3 border shadow-sm", + style: { + maxHeight: '220px', + objectFit: 'contain' + } + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer p-2 bg-light", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-secondary btn-sm", + onClick: () => setScanTarget(null), + children: "Cancel" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success btn-sm fw-bold px-3", + onClick: handleSaveScanDocument, + disabled: !scanImageBase64, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cloud-upload-fill me-1" + }), " Save Document to Chart"] + })] + })] + }) + }) + }), cropSrc && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.85)', + zIndex: 10000 + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2", + children: [/*#__PURE__*/_jsxs("h6", { + className: "modal-title fw-bold mb-0", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-crop me-2 text-success" + }), " Crop Document Photo"] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: cancelCrop + })] + }), /*#__PURE__*/_jsx("div", { + className: "modal-body p-2 text-center bg-black", + style: { + maxHeight: '65vh', + overflow: 'hidden' + }, + children: /*#__PURE__*/_jsx("div", { + style: { + maxHeight: '60vh', + width: '100%' + }, + children: /*#__PURE__*/_jsx("img", { + ref: imageRef, + src: cropSrc, + alt: "Crop Target", + style: { + maxWidth: '100%', + display: 'block' + } + }) + }) + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer p-2 bg-dark d-flex justify-content-between align-items-center flex-wrap gap-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex gap-1", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-light px-2", + onClick: () => cropper && cropper.rotate(-90), + title: "Rotate Left 90°", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-counterclockwise" + }), " 90°"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-light px-2", + onClick: () => cropper && cropper.rotate(90), + title: "Rotate Right 90°", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-clockwise" + }), " 90°"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-outline-light px-2", + onClick: () => cropper && cropper.reset(), + title: "Reset Crop Box", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-aspect-ratio" + }), " Reset"] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-secondary", + onClick: cancelCrop, + children: "Cancel" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-success fw-bold px-3", + onClick: applyCrop, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-lg me-1" + }), " Apply Crop & Save Photo"] + })] + })] + })] + }) + }) + }), /*#__PURE__*/_jsxs("div", { + className: "bottom-dock-container", + children: [/*#__PURE__*/_jsxs("button", { + className: "bottom-dock-btn btn-scan", + onClick: () => openPatientSearch('scan'), + title: "Scan Barcode / QR or Search Patient", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-qr-code-scan fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "Scan / Search" + })] + }), /*#__PURE__*/_jsxs("button", { + className: "bottom-dock-btn btn-vitals", + onClick: () => { + if (activeBed) { + openWellnessModal({ + id: activeBed.p_id || activeBed.patient_id, + p_code: activeBed.uhid, + fullName: activeBed.patient_name, + abha_id: activeBed.abha_id, + gender: activeBed.gender + }); + } else { + openPatientSearch('type'); + } + }, + title: "Add ABDM M2 Wellness Vitals", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "ABDM Vitals" + })] + }), /*#__PURE__*/_jsxs("button", { + className: "bottom-dock-btn btn-doc", + onClick: () => { + if (activeBed) { + openDocModal({ + id: activeBed.p_id || activeBed.patient_id, + p_code: activeBed.uhid, + fullName: activeBed.patient_name, + abha_id: activeBed.abha_id + }); + } else { + openPatientSearch('type'); + } + }, + title: "Add ABDM M2 Health Document (Scan/Photo)", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-medical-fill fs-5" + }), /*#__PURE__*/_jsx("span", { + children: "ABDM Health Doc" + })] + })] + }), showPatientSearchModal && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.65)', + zIndex: 1050 + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-upc-scan fs-5 text-primary" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold mb-0", + children: "Search Patient by Barcode, QR & Name" + }), /*#__PURE__*/_jsx("small", { + className: "text-white-50", + style: { + fontSize: '11px' + }, + children: "Scan Hospital Card Barcode, ABHA QR, or search registered patients" + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: closePatientSearch + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "segmented-tabs mb-3", + children: [/*#__PURE__*/_jsxs("button", { + className: `segmented-tab ${searchModalTab === 'scan' ? 'active-blue' : ''}`, + onClick: () => { + setSearchModalTab('scan'); + startBarcodeQrScanner(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera-video-fill me-1" + }), " Camera Scanner (Barcode & QR)"] + }), /*#__PURE__*/_jsxs("button", { + className: `segmented-tab ${searchModalTab === 'type' ? 'active-blue' : ''}`, + onClick: () => { + setSearchModalTab('type'); + stopBarcodeQrScanner(); + }, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-search me-1" + }), " Manual Search (UHID / Mobile / ABHA)"] + })] + }), searchModalTab === 'scan' && /*#__PURE__*/_jsxs("div", { + className: "text-center mb-3", + children: [/*#__PURE__*/_jsx("div", { + className: "qr-scanner-wrapper mx-auto mb-2", + style: { + maxWidth: '420px' + }, + children: /*#__PURE__*/_jsx("div", { + id: "patient-qr-reader", + style: { + width: '100%' + } + }) + }), scannerError ? /*#__PURE__*/_jsxs("div", { + className: "alert alert-warning py-2 px-3 small d-inline-block", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-exclamation-triangle-fill me-1" + }), " ", scannerError] + }) : /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-info-circle me-1" + }), " Point camera at ", /*#__PURE__*/_jsx("strong", { + children: "Patient Card Barcode" + }), " or ", /*#__PURE__*/_jsx("strong", { + children: "ABHA QR Code" + }), " to scan instantly."] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "input-group mb-3", + children: [/*#__PURE__*/_jsx("span", { + className: "input-group-text bg-white border-end-0", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-search text-muted" + }) + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control border-start-0 ps-0", + placeholder: "Search by UHID (P...), ABHA No, Mobile (98...), Name...", + value: patientSearchQuery, + onChange: e => { + setPatientSearchQuery(e.target.value); + executePatientSearch(e.target.value); + }, + onKeyDown: e => { + if (e.key === 'Enter') executePatientSearch(patientSearchQuery); + } + }), patientSearchQuery && /*#__PURE__*/_jsx("button", { + className: "btn btn-outline-secondary", + onClick: () => { + setPatientSearchQuery(''); + setPatientSearchResults([]); + }, + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-x" + }) + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-primary fw-bold px-3", + onClick: () => executePatientSearch(patientSearchQuery), + children: searchingPatient ? /*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm" + }) : 'Search' + })] + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center mb-2", + children: [/*#__PURE__*/_jsxs("strong", { + className: "small text-secondary text-uppercase", + children: ["Matched Patients (", patientSearchResults.length, ")"] + }), searchingPatient && /*#__PURE__*/_jsx("span", { + className: "badge bg-primary-subtle text-primary", + children: "Searching..." + })] + }), patientSearchResults.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-4 bg-light rounded-3 border", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-badge fs-2 text-muted opacity-50 d-block mb-1" + }), /*#__PURE__*/_jsx("p", { + className: "small text-muted mb-0", + children: patientSearchQuery ? 'No patients found matching this query.' : 'Type patient name, UHID, ABHA number or scan barcode above.' + })] + }) : /*#__PURE__*/_jsx("div", { + className: "d-flex flex-column gap-2", + style: { + maxHeight: '40vh', + overflowY: 'auto' + }, + children: patientSearchResults.map(pat => /*#__PURE__*/_jsx("div", { + className: "patient-search-result-card", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start flex-wrap gap-2", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("h6", { + className: "fw-bold mb-0 text-dark", + children: pat.fullName + }), /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border", + style: { + fontSize: '11px' + }, + children: [pat.gender === '1' || pat.gender === 1 ? 'Male' : pat.gender === '2' || pat.gender === 2 ? 'Female' : 'Other', pat.dob ? ` • DOB: ${pat.dob}` : ''] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-2 mt-1 small", + children: [/*#__PURE__*/_jsxs("span", { + className: "text-danger fw-semibold", + children: ["UHID: ", pat.p_code] + }), pat.mphone1 && /*#__PURE__*/_jsxs("span", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-telephone me-1" + }), pat.mphone1] + }), pat.abha_id && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border border-success-subtle", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), "ABHA: ", pat.abha_id] + }), pat.abha_address && /*#__PURE__*/_jsx("span", { + className: "badge bg-primary-subtle text-primary border border-primary-subtle", + children: pat.abha_address + })] + }), pat.ipd_admission && /*#__PURE__*/_jsx("div", { + className: "mt-1", + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-hospital me-1" + }), " Admitted IPD: ", pat.ipd_admission.ipd_code, " (Bed ", pat.ipd_admission.bed_number || pat.ipd_admission.bed_no, ")"] + }) + }), pat.opd_today && /*#__PURE__*/_jsx("div", { + className: "mt-1", + children: /*#__PURE__*/_jsxs("span", { + className: "badge bg-success", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-calendar-check me-1" + }), " OPD Today: Token #", pat.opd_today.token_no, " (", pat.opd_today.doctor_name || 'Doctor', ")"] + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-1.5 align-items-center", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-success fw-bold rounded-3 px-2 py-1.5", + onClick: () => openWellnessModal(pat), + title: "Add ABDM M2 Wellness Vitals", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill me-1" + }), " Add Vitals"] + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-primary fw-bold rounded-3 px-2 py-1.5", + onClick: () => openDocModal(pat), + title: "Add ABDM M2 Health Document", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-medical-fill me-1" + }), " Add Doc"] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-sm btn-outline-secondary rounded-3 px-2 py-1.5", + onClick: () => openWellnessHistory(pat), + title: "View Vitals History", + children: /*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history" + }) + }), pat.ipd_admission && /*#__PURE__*/_jsxs("button", { + className: "btn btn-sm btn-dark rounded-3 px-2 py-1.5", + onClick: () => { + closePatientSearch(); + openWorkspace({ + ipd_id: pat.ipd_admission.ipd_id, + patient_name: pat.fullName, + uhid: pat.p_code, + ipd_code: pat.ipd_admission.ipd_code, + bed_number: pat.ipd_admission.bed_number, + ward_name: pat.ipd_admission.ward_name, + status: 'occupied' + }); + }, + title: "Go to IPD Bedside Care", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-arrow-right-circle" + }), " IPD Bed"] + })] + })] + }) + }, pat.id)) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer p-2 bg-light d-flex justify-content-between", + children: [/*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-lock me-1" + }), " ABDM M2 Standard Compliance"] + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-secondary btn-sm px-3", + onClick: closePatientSearch, + children: "Close" + })] + })] + }) + }) + }), activeWellnessPatient && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.65)', + zIndex: 1060 + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-success text-white py-2.5", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold mb-0", + children: "Record ABDM M2 Wellness & Vitals" + }), /*#__PURE__*/_jsx("small", { + className: "text-white-50", + style: { + fontSize: '11px' + }, + children: "NRCES FHIR R4 Compliant Comprehensive Health & Wellness Suite" + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: () => setActiveWellnessPatient(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsx("div", { + className: "p-2.5 rounded-3 bg-light border mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-center flex-wrap gap-2", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("strong", { + className: "fs-6 text-dark me-2", + children: activeWellnessPatient.fullName || activeWellnessPatient.p_fname + }), /*#__PURE__*/_jsx("span", { + className: "badge bg-secondary me-1", + children: activeWellnessPatient.gender ? activeWellnessPatient.gender.toUpperCase() : 'PATIENT' + }), activeWellnessPatient.age && /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border me-1", + children: [activeWellnessPatient.age, " Yrs"] + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted mt-0.5", + children: ["UHID: ", /*#__PURE__*/_jsx("span", { + className: "text-danger fw-bold", + children: activeWellnessPatient.p_code || activeWellnessPatient.uhid + }), activeWellnessPatient.mphone1 && ` • Phone: ${activeWellnessPatient.mphone1}`] + })] + }), /*#__PURE__*/_jsx("div", { + children: activeWellnessPatient.abha_id ? /*#__PURE__*/_jsxs("span", { + className: "badge bg-success", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " ABHA: ", activeWellnessPatient.abha_id] + }) : /*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary-subtle text-secondary border", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-exclamation me-1" + }), " ABHA Not Linked"] + }) + })] + }) + }), /*#__PURE__*/_jsxs("ul", { + className: "nav nav-pills nav-fill bg-light p-1 rounded-3 mb-3 border small", + children: [/*#__PURE__*/_jsx("li", { + className: "nav-item", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: `nav-link py-1.5 px-2 fw-semibold d-flex align-items-center justify-content-center gap-1 ${wellnessModalTab === 'vitals' ? 'active shadow-sm' : 'text-secondary'}`, + onClick: () => setWellnessModalTab('vitals'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse-fill text-danger" + }), /*#__PURE__*/_jsx("span", { + children: "Vitals & Triage" + }), (wellnessForm.bp_systolic || wellnessForm.pulse_rate || wellnessForm.temperature_f) && /*#__PURE__*/_jsx("span", { + className: "badge rounded-pill bg-success p-1 ms-1", + style: { + fontSize: '7px' + }, + children: "✓" + })] + }) + }), /*#__PURE__*/_jsx("li", { + className: "nav-item", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: `nav-link py-1.5 px-2 fw-semibold d-flex align-items-center justify-content-center gap-1 ${wellnessModalTab === 'sugar' ? 'active shadow-sm' : 'text-secondary'}`, + onClick: () => setWellnessModalTab('sugar'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-droplet-half text-danger" + }), /*#__PURE__*/_jsx("span", { + children: "Sugar & Labs" + }), (wellnessForm.sugar_random || wellnessForm.sugar_fasting || wellnessForm.sugar_pp || wellnessForm.hba1c || wellnessForm.hemoglobin) && /*#__PURE__*/_jsx("span", { + className: "badge rounded-pill bg-success p-1 ms-1", + style: { + fontSize: '7px' + }, + children: "✓" + })] + }) + }), /*#__PURE__*/_jsx("li", { + className: "nav-item", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: `nav-link py-1.5 px-2 fw-semibold d-flex align-items-center justify-content-center gap-1 ${wellnessModalTab === 'activity' ? 'active shadow-sm' : 'text-secondary'}`, + onClick: () => setWellnessModalTab('activity'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-person-bounding-box text-primary" + }), /*#__PURE__*/_jsx("span", { + children: "Waist & Activity" + }), (wellnessForm.waist_circumference_cm || wellnessForm.hip_circumference_cm || wellnessForm.daily_steps || wellnessForm.sleep_hours) && /*#__PURE__*/_jsx("span", { + className: "badge rounded-pill bg-success p-1 ms-1", + style: { + fontSize: '7px' + }, + children: "✓" + })] + }) + }), /*#__PURE__*/_jsx("li", { + className: "nav-item", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: `nav-link py-1.5 px-2 fw-semibold d-flex align-items-center justify-content-center gap-1 ${wellnessModalTab === 'lifestyle' ? 'active shadow-sm' : 'text-secondary'}`, + onClick: () => setWellnessModalTab('lifestyle'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-apple text-success" + }), /*#__PURE__*/_jsx("span", { + children: "Lifestyle & Notes" + }), (wellnessForm.diet_type || wellnessForm.tobacco_status || wellnessForm.diet_lifestyle_note || wellnessForm.general_advice) && /*#__PURE__*/_jsx("span", { + className: "badge rounded-pill bg-success p-1 ms-1", + style: { + fontSize: '7px' + }, + children: "✓" + })] + }) + }), String(activeWellnessPatient.gender || '').toLowerCase() !== 'male' && /*#__PURE__*/_jsx("li", { + className: "nav-item", + children: /*#__PURE__*/_jsxs("button", { + type: "button", + className: `nav-link py-1.5 px-2 fw-semibold d-flex align-items-center justify-content-center gap-1 ${wellnessModalTab === 'women' ? 'active shadow-sm' : 'text-secondary'}`, + onClick: () => setWellnessModalTab('women'), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-gender-female text-warning" + }), /*#__PURE__*/_jsx("span", { + children: "Women's Health" + }), (wellnessForm.women_lmp || wellnessForm.women_pregnancy_status) && /*#__PURE__*/_jsx("span", { + className: "badge rounded-pill bg-success p-1 ms-1", + style: { + fontSize: '7px' + }, + children: "✓" + })] + }) + })] + }), wellnessModalTab === 'vitals' && /*#__PURE__*/_jsxs("div", { + className: "row g-2.5 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "BP Sys/Dia (mmHg)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control text-center", + placeholder: "120", + value: wellnessForm.bp_systolic, + onChange: e => setWellnessForm({ + ...wellnessForm, + bp_systolic: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text px-1", + children: "/" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control text-center", + placeholder: "80", + value: wellnessForm.bp_diastolic, + onChange: e => setWellnessForm({ + ...wellnessForm, + bp_diastolic: e.target.value + }) + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Pulse Rate (bpm)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "72", + value: wellnessForm.pulse_rate, + onChange: e => setWellnessForm({ + ...wellnessForm, + pulse_rate: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "SpO2 %" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "98", + value: wellnessForm.spo2, + onChange: e => setWellnessForm({ + ...wellnessForm, + spo2: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Temp °F" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control form-control-sm text-center", + placeholder: "98.6", + value: wellnessForm.temperature_f, + onChange: e => setWellnessForm({ + ...wellnessForm, + temperature_f: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Resp Rate (/min)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + className: "form-control form-control-sm text-center", + placeholder: "18", + value: wellnessForm.resp_rate, + onChange: e => setWellnessForm({ + ...wellnessForm, + resp_rate: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Height (cm)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control form-control-sm text-center", + placeholder: "165", + value: wellnessForm.height_cm, + onChange: e => setWellnessForm({ + ...wellnessForm, + height_cm: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Weight (kg)" + }), /*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control form-control-sm text-center", + placeholder: "70", + value: wellnessForm.weight_kg, + onChange: e => setWellnessForm({ + ...wellnessForm, + weight_kg: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-3", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Calculated BMI" + }), /*#__PURE__*/_jsx("div", { + className: "input-group input-group-sm", + children: /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm text-center bg-light fw-bold", + readOnly: true, + value: wellnessForm.height_cm && wellnessForm.weight_kg && parseFloat(wellnessForm.height_cm) > 0 ? (parseFloat(wellnessForm.weight_kg) / Math.pow(parseFloat(wellnessForm.height_cm) / 100, 2)).toFixed(2) : '-' + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 mt-2", + children: [/*#__PURE__*/_jsxs("label", { + className: "form-label small mb-1 fw-bold d-flex justify-content-between", + children: [/*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-emoji-frown me-1 text-warning" + }), " Pain Severity Score (0 - 10 VRS)"] + }), /*#__PURE__*/_jsx("span", { + className: "text-muted fw-normal", + children: wellnessForm.pain_score === '' ? 'Not assessed' : wellnessForm.pain_score == 0 ? '0 - No Pain' : wellnessForm.pain_score <= 3 ? `${wellnessForm.pain_score} - Mild Pain` : wellnessForm.pain_score <= 6 ? `${wellnessForm.pain_score} - Moderate Pain` : `${wellnessForm.pain_score} - Severe Pain` + })] + }), /*#__PURE__*/_jsx("div", { + className: "d-flex gap-1 flex-wrap", + children: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(val => /*#__PURE__*/_jsx("button", { + type: "button", + className: `btn btn-sm flex-fill py-1 px-1.5 ${wellnessForm.pain_score === String(val) ? val === 0 ? 'btn-success text-white' : val <= 3 ? 'btn-info text-white' : val <= 6 ? 'btn-warning text-dark' : 'btn-danger text-white' : 'btn-outline-secondary'}`, + onClick: () => setWellnessForm({ + ...wellnessForm, + pain_score: wellnessForm.pain_score === String(val) ? '' : String(val) + }), + children: val + }, val)) + })] + })] + }), wellnessModalTab === 'sugar' && /*#__PURE__*/_jsxs("div", { + className: "row g-2.5 mb-2", + children: [/*#__PURE__*/_jsx("div", { + className: "col-12", + children: /*#__PURE__*/_jsxs("div", { + className: "alert alert-info py-1.5 px-3 small d-flex align-items-center gap-2 mb-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-info-circle-fill fs-6 text-primary" + }), /*#__PURE__*/_jsxs("span", { + children: ["Point-of-care capillary blood sugar & POC lab values (NRCES ", /*#__PURE__*/_jsx("strong", { + children: "GeneralAssessment" + }), " slice)"] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Random Blood Sugar (RBS)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "1", + className: "form-control text-center", + placeholder: "110", + value: wellnessForm.sugar_random, + onChange: e => setWellnessForm({ + ...wellnessForm, + sugar_random: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "mg/dL" + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: "Normal: < 140 mg/dL" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Fasting Blood Sugar (FBS)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "1", + className: "form-control text-center", + placeholder: "95", + value: wellnessForm.sugar_fasting, + onChange: e => setWellnessForm({ + ...wellnessForm, + sugar_fasting: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "mg/dL" + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: "Normal: 70 - 100 mg/dL" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Post-Prandial (PPBS)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "1", + className: "form-control text-center", + placeholder: "130", + value: wellnessForm.sugar_pp, + onChange: e => setWellnessForm({ + ...wellnessForm, + sugar_pp: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "mg/dL" + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: "Normal: < 140 mg/dL (2h post meal)" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "HbA1c (Glycated Hemoglobin)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control text-center", + placeholder: "5.6", + value: wellnessForm.hba1c, + onChange: e => setWellnessForm({ + ...wellnessForm, + hba1c: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "%" + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: "Normal: < 5.7% | Prediabetes: 5.7-6.4% | Diabetes: ≥ 6.5%" + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "POC Hemoglobin (Hb)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control text-center", + placeholder: "13.5", + value: wellnessForm.hemoglobin, + onChange: e => setWellnessForm({ + ...wellnessForm, + hemoglobin: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "g/dL" + })] + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: "Normal: 12.0 - 17.5 g/dL" + })] + })] + }), wellnessModalTab === 'activity' && /*#__PURE__*/_jsxs("div", { + className: "row g-2.5 mb-2", + children: [/*#__PURE__*/_jsx("div", { + className: "col-12", + children: /*#__PURE__*/_jsxs("h6", { + className: "fw-bold small text-primary mb-1 border-bottom pb-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-rulers me-1" + }), " Body Circumferences (NRCES BodyMeasurement)"] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Waist Circumference" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control text-center", + placeholder: "85", + value: wellnessForm.waist_circumference_cm, + onChange: e => setWellnessForm({ + ...wellnessForm, + waist_circumference_cm: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "cm" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Hip Circumference" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "0.1", + className: "form-control text-center", + placeholder: "95", + value: wellnessForm.hip_circumference_cm, + onChange: e => setWellnessForm({ + ...wellnessForm, + hip_circumference_cm: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "cm" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Waist-to-Hip Ratio (WHR)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm text-center bg-light fw-bold", + readOnly: true, + value: wellnessForm.waist_circumference_cm && wellnessForm.hip_circumference_cm && parseFloat(wellnessForm.hip_circumference_cm) > 0 ? (parseFloat(wellnessForm.waist_circumference_cm) / parseFloat(wellnessForm.hip_circumference_cm)).toFixed(2) : '-' + }), /*#__PURE__*/_jsx("small", { + className: "text-muted", + style: { + fontSize: '10px' + }, + children: "Normal: Men < 0.90 | Women < 0.85" + })] + }), /*#__PURE__*/_jsx("div", { + className: "col-12 mt-2", + children: /*#__PURE__*/_jsxs("h6", { + className: "fw-bold small text-success mb-1 border-bottom pb-1", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-activity me-1" + }), " Physical Activity & Sleep (NRCES PhysicalActivity)"] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Daily Steps (24h)" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "100", + className: "form-control text-center", + placeholder: "8000", + value: wellnessForm.daily_steps, + onChange: e => setWellnessForm({ + ...wellnessForm, + daily_steps: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "steps" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Sleep Duration" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "0.5", + className: "form-control text-center", + placeholder: "7.5", + value: wellnessForm.sleep_hours, + onChange: e => setWellnessForm({ + ...wellnessForm, + sleep_hours: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "hours" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Exercise Duration" + }), /*#__PURE__*/_jsxs("div", { + className: "input-group input-group-sm", + children: [/*#__PURE__*/_jsx("input", { + type: "number", + step: "5", + className: "form-control text-center", + placeholder: "30", + value: wellnessForm.exercise_min_per_day, + onChange: e => setWellnessForm({ + ...wellnessForm, + exercise_min_per_day: e.target.value + }) + }), /*#__PURE__*/_jsx("span", { + className: "input-group-text", + children: "min/day" + })] + })] + })] + }), wellnessModalTab === 'lifestyle' && /*#__PURE__*/_jsxs("div", { + className: "row g-2.5 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Diet Pattern (ABDM)" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: wellnessForm.diet_type, + onChange: e => setWellnessForm({ + ...wellnessForm, + diet_type: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "Select diet..." + }), /*#__PURE__*/_jsx("option", { + value: "Balanced Diet", + children: "Balanced Diet" + }), /*#__PURE__*/_jsx("option", { + value: "Vegetarian", + children: "Vegetarian" + }), /*#__PURE__*/_jsx("option", { + value: "Lacto-Vegetarian", + children: "Lacto-Vegetarian" + }), /*#__PURE__*/_jsx("option", { + value: "Non-Vegetarian", + children: "Non-Vegetarian" + }), /*#__PURE__*/_jsx("option", { + value: "Vegan", + children: "Vegan" + }), /*#__PURE__*/_jsx("option", { + value: "Diabetic Diet", + children: "Diabetic Diet (Low GI)" + }), /*#__PURE__*/_jsx("option", { + value: "Low Sodium / DASH Diet", + children: "Low Sodium / DASH Diet" + }), /*#__PURE__*/_jsx("option", { + value: "Renal Diet", + children: "Renal Diet" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Tobacco / Smoking" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: wellnessForm.tobacco_status, + onChange: e => setWellnessForm({ + ...wellnessForm, + tobacco_status: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "Select status..." + }), /*#__PURE__*/_jsx("option", { + value: "Never Smoked", + children: "Never Smoked" + }), /*#__PURE__*/_jsx("option", { + value: "Former / Ex-Smoker", + children: "Former / Ex-Smoker" + }), /*#__PURE__*/_jsx("option", { + value: "Current Smoker (Occasional)", + children: "Current Smoker (Occasional)" + }), /*#__PURE__*/_jsx("option", { + value: "Current Smoker (Daily)", + children: "Current Smoker (Daily)" + }), /*#__PURE__*/_jsx("option", { + value: "Tobacco Chewer", + children: "Tobacco Chewer" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-6 col-md-4", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Alcohol Consumption" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: wellnessForm.alcohol_status, + onChange: e => setWellnessForm({ + ...wellnessForm, + alcohol_status: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "Select status..." + }), /*#__PURE__*/_jsx("option", { + value: "Lifetime Non-Drinker", + children: "Lifetime Non-Drinker" + }), /*#__PURE__*/_jsx("option", { + value: "Former Drinker", + children: "Former Drinker" + }), /*#__PURE__*/_jsx("option", { + value: "Occasional / Social Drinker", + children: "Occasional / Social Drinker" + }), /*#__PURE__*/_jsx("option", { + value: "Regular Drinker", + children: "Regular Drinker" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Diet & Lifestyle Guidance (ABDM)" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Low sodium diet, 30 min daily brisk walking, adequate hydration", + value: wellnessForm.diet_lifestyle_note, + onChange: e => setWellnessForm({ + ...wellnessForm, + diet_lifestyle_note: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "General Nursing Observations" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Patient conscious, oriented to time/place, vitals within acceptable limits", + value: wellnessForm.general_advice, + onChange: e => setWellnessForm({ + ...wellnessForm, + general_advice: e.target.value + }) + })] + })] + }), wellnessModalTab === 'women' && /*#__PURE__*/_jsxs("div", { + className: "row g-2.5 mb-2", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Last Menstrual Period (LMP Date)" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: wellnessForm.women_lmp, + onChange: e => setWellnessForm({ + ...wellnessForm, + women_lmp: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small mb-1 fw-bold", + children: "Pregnancy / Reproductive Status" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: wellnessForm.women_pregnancy_status, + onChange: e => setWellnessForm({ + ...wellnessForm, + women_pregnancy_status: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "", + children: "Select reproductive status..." + }), /*#__PURE__*/_jsx("option", { + value: "Not Pregnant", + children: "Not Pregnant" + }), /*#__PURE__*/_jsx("option", { + value: "Pregnant - 1st Trimester (1 - 12 wks)", + children: "Pregnant - 1st Trimester (1 - 12 wks)" + }), /*#__PURE__*/_jsx("option", { + value: "Pregnant - 2nd Trimester (13 - 26 wks)", + children: "Pregnant - 2nd Trimester (13 - 26 wks)" + }), /*#__PURE__*/_jsx("option", { + value: "Pregnant - 3rd Trimester (27 - 40+ wks)", + children: "Pregnant - 3rd Trimester (27 - 40+ wks)" + }), /*#__PURE__*/_jsx("option", { + value: "Postpartum (< 6 weeks post delivery)", + children: "Postpartum (< 6 weeks post delivery)" + }), /*#__PURE__*/_jsx("option", { + value: "Lactating / Breastfeeding", + children: "Lactating / Breastfeeding" + }), /*#__PURE__*/_jsx("option", { + value: "Perimenopausal", + children: "Perimenopausal" + }), /*#__PURE__*/_jsx("option", { + value: "Postmenopausal", + children: "Postmenopausal" + })] + })] + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer p-2 bg-light d-flex justify-content-between", + children: [/*#__PURE__*/_jsxs("button", { + className: "btn btn-outline-secondary btn-sm", + onClick: () => openWellnessHistory(activeWellnessPatient), + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history me-1" + }), " Past History"] + }), /*#__PURE__*/_jsxs("div", { + className: "d-flex gap-2", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-secondary btn-sm", + onClick: () => setActiveWellnessPatient(null), + children: "Cancel" + }), /*#__PURE__*/_jsxs("button", { + className: "btn btn-success btn-sm fw-bold px-3 shadow-sm", + onClick: handleSaveWellness, + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle-fill me-1" + }), " Save ABDM Wellness Vitals"] + })] + })] + })] + }) + }) + }), activeDocPatient && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.65)', + zIndex: 1060 + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-lg", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-primary text-white py-2.5", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-file-earmark-medical-fill fs-5" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold mb-0", + children: "Add ABDM M2 Health Document" + }), /*#__PURE__*/_jsx("small", { + className: "text-white-50", + style: { + fontSize: '11px' + }, + children: "Scan paper prescriptions, lab reports or clinical documents" + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: () => setActiveDocPatient(null) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-body p-3", + children: [/*#__PURE__*/_jsx("div", { + className: "p-2.5 rounded-3 bg-light border mb-3", + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex justify-content-between align-items-start flex-wrap gap-1", + children: [/*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("strong", { + className: "fs-6 text-dark", + children: activeDocPatient.fullName || activeDocPatient.p_fname + }), /*#__PURE__*/_jsxs("div", { + className: "small text-muted", + children: ["UHID: ", /*#__PURE__*/_jsx("span", { + className: "text-danger fw-bold", + children: activeDocPatient.p_code || activeDocPatient.uhid + })] + })] + }), activeDocPatient.abha_id && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-shield-check me-1" + }), " ABHA: ", activeDocPatient.abha_id] + })] + }) + }), /*#__PURE__*/_jsxs("div", { + className: "row g-2 mb-3", + children: [/*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Document Category (ABDM HI Type)" + }), /*#__PURE__*/_jsxs("select", { + className: "form-select form-select-sm", + value: patientDocForm.document_type, + onChange: e => setPatientDocForm({ + ...patientDocForm, + document_type: e.target.value + }), + children: [/*#__PURE__*/_jsx("option", { + value: "Prescription", + children: "Prescription Record (PrescriptionRecord)" + }), /*#__PURE__*/_jsx("option", { + value: "Diagnostic Report / Lab", + children: "Diagnostic / Lab Report (DiagnosticReport)" + }), /*#__PURE__*/_jsx("option", { + value: "Discharge Summary", + children: "Discharge Summary (DischargeSummary)" + }), /*#__PURE__*/_jsx("option", { + value: "Scan / Radiology (X-Ray/CT/MRI)", + children: "Radiology / Scan (HealthDocumentRecord)" + }), /*#__PURE__*/_jsx("option", { + value: "Paper Medical Record", + children: "Paper Medical Record (HealthDocumentRecord)" + }), /*#__PURE__*/_jsx("option", { + value: "Immunization Record", + children: "Immunization Record (ImmunizationRecord)" + }), /*#__PURE__*/_jsx("option", { + value: "Health Document", + children: "Other Health Document (HealthDocumentRecord)" + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12 col-md-6", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Document Date" + }), /*#__PURE__*/_jsx("input", { + type: "date", + className: "form-control form-control-sm", + value: patientDocForm.document_date, + onChange: e => setPatientDocForm({ + ...patientDocForm, + document_date: e.target.value + }) + })] + }), /*#__PURE__*/_jsxs("div", { + className: "col-12", + children: [/*#__PURE__*/_jsx("label", { + className: "form-label small fw-bold mb-1", + children: "Remarks / Document Title" + }), /*#__PURE__*/_jsx("input", { + type: "text", + className: "form-control form-control-sm", + placeholder: "e.g. Chest X-Ray Report, Blood CBC Test, Consultation Note", + value: patientDocForm.remarks, + onChange: e => setPatientDocForm({ + ...patientDocForm, + remarks: e.target.value + }) + })] + })] + }), /*#__PURE__*/_jsx("div", { + className: "mb-3 text-center", + children: /*#__PURE__*/_jsxs("label", { + className: "btn btn-primary btn-lg w-100 py-3 fw-bold rounded-3 shadow-sm", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-camera me-2" + }), " Take Document Photo / Choose Image", /*#__PURE__*/_jsx("input", { + type: "file", + accept: "image/*", + capture: "environment", + className: "d-none", + onChange: handleScanImageCapture + })] + }) + }), scanImagePreview && /*#__PURE__*/_jsxs("div", { + className: "position-relative p-2 border rounded-3 bg-light text-center", + children: [/*#__PURE__*/_jsxs("span", { + className: "badge bg-success position-absolute top-0 start-0 m-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-check-circle me-1" + }), " Document Photo Captured"] + }), /*#__PURE__*/_jsx("img", { + src: scanImagePreview, + alt: "Document Scan Preview", + className: "img-fluid rounded-3 border shadow-sm", + style: { + maxHeight: '200px', + objectFit: 'contain' + } + })] + })] + }), /*#__PURE__*/_jsxs("div", { + className: "modal-footer p-2 bg-light", + children: [/*#__PURE__*/_jsx("button", { + className: "btn btn-secondary btn-sm", + onClick: () => setActiveDocPatient(null), + disabled: isSavingDoc, + children: "Cancel" + }), /*#__PURE__*/_jsx("button", { + className: "btn btn-primary btn-sm fw-bold px-3", + onClick: handleSavePatientDocument, + disabled: !scanImageBase64 || isSavingDoc, + children: isSavingDoc ? /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("span", { + className: "spinner-border spinner-border-sm me-1", + role: "status", + "aria-hidden": "true" + }), "Uploading..."] + }) : /*#__PURE__*/_jsxs("span", { + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-cloud-upload-fill me-1" + }), " Upload ABDM Health Document"] + }) + })] + })] + }) + }) + }), wellnessHistoryPatient && /*#__PURE__*/_jsx("div", { + className: "modal show d-block", + style: { + backgroundColor: 'rgba(0,0,0,0.65)', + zIndex: 1070 + }, + children: /*#__PURE__*/_jsx("div", { + className: "modal-dialog modal-dialog-centered modal-xl", + children: /*#__PURE__*/_jsxs("div", { + className: "modal-content rounded-4 border-0 shadow-lg overflow-hidden", + children: [/*#__PURE__*/_jsxs("div", { + className: "modal-header bg-dark text-white py-2.5", + children: [/*#__PURE__*/_jsxs("div", { + className: "d-flex align-items-center gap-2", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-clock-history fs-5 text-warning" + }), /*#__PURE__*/_jsxs("div", { + children: [/*#__PURE__*/_jsx("h6", { + className: "modal-title fw-bold mb-0", + children: "Vitals & Wellness History" + }), /*#__PURE__*/_jsxs("small", { + className: "text-white-50", + style: { + fontSize: '11px' + }, + children: [wellnessHistoryPatient.fullName || wellnessHistoryPatient.p_fname, " (UHID: ", wellnessHistoryPatient.p_code || wellnessHistoryPatient.uhid, ")"] + })] + })] + }), /*#__PURE__*/_jsx("button", { + className: "btn-close btn-close-white", + onClick: () => setWellnessHistoryPatient(null) + })] + }), /*#__PURE__*/_jsx("div", { + className: "modal-body p-3", + children: loadingHistory ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-4", + children: [/*#__PURE__*/_jsx("div", { + className: "spinner-border text-primary", + role: "status" + }), /*#__PURE__*/_jsx("p", { + className: "small text-muted mt-2", + children: "Loading historical vitals..." + })] + }) : wellnessHistoryList.length === 0 ? /*#__PURE__*/_jsxs("div", { + className: "text-center py-4 bg-light rounded-3", + children: [/*#__PURE__*/_jsx("i", { + className: "bi bi-heart-pulse fs-2 text-muted opacity-50 d-block mb-1" + }), /*#__PURE__*/_jsx("p", { + className: "small text-muted mb-0", + children: "No past vitals or wellness entries recorded yet for this patient." + })] + }) : /*#__PURE__*/_jsx("div", { + className: "table-responsive", + children: /*#__PURE__*/_jsxs("table", { + className: "table table-sm table-striped table-hover align-middle mb-0", + style: { + fontSize: '12px' + }, + children: [/*#__PURE__*/_jsx("thead", { + className: "table-light", + children: /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("th", { + children: "Date & Time" + }), /*#__PURE__*/_jsx("th", { + children: "Vitals (BP / Pulse / SpO2 / Temp)" + }), /*#__PURE__*/_jsx("th", { + children: "Body / BMI" + }), /*#__PURE__*/_jsx("th", { + children: "Blood Glucose (mg/dL)" + }), /*#__PURE__*/_jsx("th", { + children: "POC Labs" + }), /*#__PURE__*/_jsx("th", { + children: "Activity / Lifestyle" + }), /*#__PURE__*/_jsx("th", { + children: "Staff" + }), /*#__PURE__*/_jsx("th", { + children: "Advice / Remarks" + })] + }) + }), /*#__PURE__*/_jsx("tbody", { + children: wellnessHistoryList.map(rec => /*#__PURE__*/_jsxs("tr", { + children: [/*#__PURE__*/_jsx("td", { + className: "fw-semibold text-nowrap", + children: formatDateTime(rec.recorded_at) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-1 align-items-center", + children: [rec.bp_systolic && /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border", + children: ["BP ", rec.bp_systolic, "/", rec.bp_diastolic] + }), rec.pulse_rate && /*#__PURE__*/_jsxs("span", { + className: "badge bg-light text-dark border", + children: [rec.pulse_rate, " bpm"] + }), rec.spo2 && /*#__PURE__*/_jsxs("span", { + className: "badge bg-info-subtle text-info border border-info-subtle", + children: [rec.spo2, "% O2"] + }), rec.temperature_f && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border border-danger-subtle", + children: [rec.temperature_f, "°F"] + }), rec.pain_score !== null && rec.pain_score !== undefined && rec.pain_score !== '' && /*#__PURE__*/_jsxs("span", { + className: `badge ${rec.pain_score == 0 ? 'bg-success-subtle text-success' : rec.pain_score <= 3 ? 'bg-info-subtle text-info' : 'bg-warning-subtle text-warning-emphasis'}`, + children: ["Pain: ", rec.pain_score, "/10"] + })] + }) + }), /*#__PURE__*/_jsxs("td", { + children: [/*#__PURE__*/_jsxs("div", { + children: [rec.bmi && /*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary-subtle text-secondary me-1", + children: ["BMI ", rec.bmi] + }), rec.weight_kg && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [rec.weight_kg, "kg "] + }), rec.height_cm && /*#__PURE__*/_jsxs("small", { + className: "text-muted", + children: [rec.height_cm, "cm"] + })] + }), (rec.waist_circumference_cm || rec.waist_hip_ratio) && /*#__PURE__*/_jsxs("small", { + className: "text-muted d-block", + style: { + fontSize: '11px' + }, + children: [rec.waist_circumference_cm ? `Waist: ${rec.waist_circumference_cm}cm` : '', rec.waist_hip_ratio ? ` • WHR: ${rec.waist_hip_ratio}` : ''] + })] + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-1", + children: [rec.sugar_random && /*#__PURE__*/_jsxs("span", { + className: "badge bg-warning-subtle text-warning-emphasis border", + children: ["RBS: ", rec.sugar_random] + }), rec.sugar_fasting && /*#__PURE__*/_jsxs("span", { + className: "badge bg-primary-subtle text-primary border", + children: ["FBS: ", rec.sugar_fasting] + }), rec.sugar_pp && /*#__PURE__*/_jsxs("span", { + className: "badge bg-secondary-subtle text-secondary border", + children: ["PP: ", rec.sugar_pp] + }), !rec.sugar_random && !rec.sugar_fasting && !rec.sugar_pp && /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "-" + })] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("div", { + className: "d-flex flex-wrap gap-1", + children: [rec.hemoglobin && /*#__PURE__*/_jsxs("span", { + className: "badge bg-danger-subtle text-danger border", + children: ["Hb: ", rec.hemoglobin, " g/dL"] + }), rec.hba1c && /*#__PURE__*/_jsxs("span", { + className: "badge bg-success-subtle text-success border", + children: ["A1c: ", rec.hba1c, "%"] + }), !rec.hemoglobin && !rec.hba1c && /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "-" + })] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsxs("div", { + className: "small", + children: [rec.diet_type && /*#__PURE__*/_jsx("span", { + className: "badge bg-light text-dark border me-1", + children: rec.diet_type + }), rec.daily_steps && /*#__PURE__*/_jsxs("span", { + className: "text-muted me-1", + children: [rec.daily_steps, " steps"] + }), rec.sleep_hours && /*#__PURE__*/_jsxs("span", { + className: "text-muted", + children: [rec.sleep_hours, "h sleep"] + }), !rec.diet_type && !rec.daily_steps && !rec.sleep_hours && /*#__PURE__*/_jsx("span", { + className: "text-muted", + children: "-" + })] + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-muted", + children: rec.recorded_by || 'Staff' + }) + }), /*#__PURE__*/_jsx("td", { + children: /*#__PURE__*/_jsx("small", { + className: "text-truncate d-inline-block", + style: { + maxWidth: '180px' + }, + title: rec.general_advice || rec.diet_lifestyle_note, + children: rec.general_advice || rec.diet_lifestyle_note || '-' + }) + })] + }, rec.id)) + })] + }) + }) + }), /*#__PURE__*/_jsx("div", { + className: "modal-footer p-2 bg-light", + children: /*#__PURE__*/_jsx("button", { + className: "btn btn-secondary btn-sm px-3", + onClick: () => setWellnessHistoryPatient(null), + children: "Close" + }) + })] + }) + }) + })] + })] + }); +} +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(/*#__PURE__*/_jsx(NursingApp, {})); \ No newline at end of file diff --git a/public/assets/vendor/jquery/jquery-3.7.1.min.js b/public/assets/vendor/jquery/jquery-3.7.1.min.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/public/assets/vendor/jquery/jquery-3.7.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/public/assets/vendor/select2/select2.min.js b/public/assets/vendor/select2/select2.min.js index 43f0a65..091d4b5 100644 --- a/public/assets/vendor/select2/select2.min.js +++ b/public/assets/vendor/select2/select2.min.js @@ -1,3 +1,2 @@ -/*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.slice(0,n.length-1).concat(a),k=0;k0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){var d=v.call(arguments,0);return"string"!=typeof d[0]&&1===d.length&&d.push(null),n.apply(b,d.concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;hc;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e":">",'"':""","'":"'","/":"/"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('
    ');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('
  • '),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),d[0].className+=" select2-results__message",this.$results.append(d)},c.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c0?b.first().trigger("mouseenter"):a.first().trigger("mouseenter"),this.ensureHighlightVisible()},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")})})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";a(h);this.template(b,h);for(var i=[],j=0;j",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("unselect",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):0>h-g&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-b+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");return"true"===c.attr("aria-selected")?void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{})):void d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html(''),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("focus",function(b){a.isOpen()||c.$selection.focus()}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},e.prototype.selectionContainer=function(){return a("")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('
      '),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},d.prototype.selectionContainer=function(){var b=a('
    • ×
    • ');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e0||0===c.length)){var d=a('×');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}});var f=document.documentMode,g=f&&11>=f;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){return g?void e.$selection.off("input.search input.searchcheck"):void e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change"); -if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()&&e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('
    • '),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a(""),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id,h=this.$container.parents().filter(b.hasScroll);h.off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.topf.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null; -},e.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery-mousewheel",["jquery"],function(a){return a}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d,f=Array.prototype.slice.call(arguments,1);return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2."),d=c[b].apply(c,f)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c}); \ No newline at end of file +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(u){var e=function(){if(u&&u.fn&&u.fn.select2&&u.fn.select2.amd)var e=u.fn.select2.amd;var t,n,r,h,o,s,f,g,m,v,y,_,i,a,b;function w(e,t){return i.call(e,t)}function l(e,t){var n,r,i,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&b.test(e[s])&&(e[s]=e[s].replace(b,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},i.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},i.__cache={};var n=0;return i.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},i.StoreData=function(e,t,n){var r=i.GetUniqueElementId(e);i.__cache[r]||(i.__cache[r]={}),i.__cache[r][t]=n},i.GetData=function(e,t){var n=i.GetUniqueElementId(e);return t?i.__cache[n]&&null!=i.__cache[n][t]?i.__cache[n][t]:o(e).data(t):i.__cache[n]},i.RemoveData=function(e){var t=i.GetUniqueElementId(e);null!=i.__cache[t]&&delete i.__cache[t],e.removeAttribute("data-select2-id")},i}),e.define("select2/results",["jquery","./utils"],function(h,f){function r(e,t,n){this.$element=e,this.data=n,this.options=t,r.__super__.constructor.call(this)}return f.Extend(r,f.Observable),r.prototype.render=function(){var e=h('
        ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},r.prototype.clear=function(){this.$results.empty()},r.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h(''),r=this.options.get("translations").get(e.message);n.append(t(r(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},r.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},r.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},r.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var r=n-1;0===e.length&&(r=0);var i=t.eq(r);i.trigger("mouseenter");var o=l.$results.offset().top,s=i.offset().top,a=l.$results.scrollTop()+(s-o);0===r?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var r=t.eq(n);r.trigger("mouseenter");var i=l.$results.offset().top+l.$results.outerHeight(!1),o=r.offset().top+r.outerHeight(!1),s=l.$results.scrollTop()+o-i;0===n?l.$results.scrollTop(0):ithis.$results.outerHeight()||o<0)&&this.$results.scrollTop(i)}},r.prototype.template=function(e,t){var n=this.options.get("templateResult"),r=this.options.get("escapeMarkup"),i=n(e,t);null==i?t.style.display="none":"string"==typeof i?t.innerHTML=r(i):h(t).append(i)},r}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,r,i){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return r.Extend(o,r.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=r.GetData(this.$element[0],"old-tabindex")?this._tabindex=r.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,r=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",r),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&r.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,r){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var r=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",r).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",r),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),r=this.display(t,n);n.empty().append(r);var i=t.title||t.text;i?n.attr("title",i):n.removeAttr("title")}else this.clear()},i}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
          '),e},n.prototype.bind=function(e,t){var r=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){r.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!r.isDisabled()){var t=i(this).parent(),n=l.GetData(t[0],"data");r.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return i('
        • ×
        • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×');a.StoreData(r[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(r)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(r,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=r('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),t.on("open",function(){r.$search.attr("aria-controls",i),r.$search.trigger("focus")}),t.on("close",function(){r.$search.val(""),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.trigger("focus")}),t.on("enable",function(){r.$search.prop("disabled",!1),r._transferTabIndex()}),t.on("disable",function(){r.$search.prop("disabled",!0)}),t.on("focus",function(e){r.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){r.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){r._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===r.$search.val()){var t=r.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("select",function(){r._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var r=this;this._checkIfMaximumSelected(function(){e.call(r,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var r=this;this.current(function(e){var t=null!=e?e.length:0;0=r.maximumSelectionLength?r.trigger("results:message",{message:"maximumSelected",args:{maximum:r.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){r.handleSearch(e)}),t.on("open",function(){r.$search.attr("tabindex",0),r.$search.attr("aria-controls",i),r.$search.trigger("focus"),window.setTimeout(function(){r.$search.trigger("focus")},0)}),t.on("close",function(){r.$search.attr("tabindex",-1),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.val(""),r.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||r.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(r.showSearch(e)?r.$searchContainer.removeClass("select2-search--hide"):r.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,r){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,r)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),r=t.length-1;0<=r;r--){var i=t[r];this.placeholder.id===i.id&&n.splice(r,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,r){this.lastParams={},e.call(this,t,n,r),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("query",function(e){r.lastParams=e,r.loading=!0}),t.on("query:append",function(e){r.lastParams=e,r.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
        • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("open",function(){r._showDropdown(),r._attachPositioningHandler(t),r._bindContainerResultHandlers(t)}),t.on("close",function(){r._hideDropdown(),r._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,r="scroll.select2."+t.id,i="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(r,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(r+" "+i+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,r="resize.select2."+t.id,i="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+r+" "+i)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),r=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=i.top,o.bottom=i.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+s,d={left:i.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(r="below"),u||!c||t?!c&&u&&t&&(r="below"):r="above",("above"==r||t&&"below"!==r)&&(d.top=o.top-h.top-s),null!=r&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+r),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+r)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,r){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,r)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,r=0;r');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("jquery-mousewheel",["jquery"],function(e){return e}),e.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,o,t,s){if(null==i.fn.select2){var a=["open","close","destroy"];i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new o(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,r=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=s.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,r)}),-1([\s\S]*?)<\/script>/); + if (!match) { + console.warn(`No with the bundle script + const babelStart = content.indexOf('', babelStart); + if (babelEnd !== -1) { + const before = content.substring(0, babelStart); + const after = content.substring(babelEnd + ''.length); + content = before + `` + after; + console.log(`Updated ${app.name}/index.html to use ${app.bundleName}`); + } else { + console.warn(`Could not find closing for ${app.name}`); + } + } else { + console.log(`${app.name}/index.html already updated`); + } + + fs.writeFileSync(htmlPath, content, 'utf8'); +} + +console.log('All PWA index.html files switched to precompiled bundles without Babel or unsafe-eval.');