1(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([typeof document === "object" ? document.currentScript : undefined, 2162656, ((__turbopack_context__) => { 3"use strict"; 4 5; 6const PRODUCT_SUPPLIER_FIELD_KEY = 'supplier'; 7const PRODUCT_SUPPLIER_FIELD_ID = `cf_${PRODUCT_SUPPLIER_FIELD_KEY}`; 8const PRODUCT_SUPPLIER_SUBMIT_ALIAS = `cf:${PRODUCT_SUPPLIER_FIELD_KEY}`; 9const PRODUCT_SUPPLIER_NONE_VALUE = '__none__'; 10const PRODUCT_SUPPLIER_HEADER = 'x-genikos-product-supplier'; 11const PRODUCT_SUPPLIER_OPTIONS_PATH = '/api/genikos_customers/supplier-options'; 12const PRODUCT_ENTITY_ID = 'catalog:catalog_product'; 13const COMPANY_ENTITY_ID = 'customers:customer_entity'; 14const SUPPLIER_COMPANY_TYPES = [ 15 'supplier', 16 'both' 17]; 18const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; 19function isSupplierCompanyType(value) { 20 return (0, __TURBOPACK__imported__module__391940__["isCompanyTypeValue"])(value) && SUPPLIER_COMPANY_TYPES.includes(value); 21} 22function isCompanyId(value) { 23 return typeof value === 'string' && UUID_PATTERN.test(value); 24} 25function readProductSupplierValue(values) { 26 if (Object.prototype.hasOwnProperty.call(values, PRODUCT_SUPPLIER_FIELD_ID)) { 27 return values[PRODUCT_SUPPLIER_FIELD_ID]; 28 } 29 if (Object.prototype.hasOwnProperty.call(values, PRODUCT_SUPPLIER_SUBMIT_ALIAS)) { 30 return values[PRODUCT_SUPPLIER_SUBMIT_ALIAS]; 31 } 32 if (Object.prototype.hasOwnProperty.call(values, PRODUCT_SUPPLIER_FIELD_KEY)) { 33 return values[PRODUCT_SUPPLIER_FIELD_KEY]; 34 } 35 const customFields = values.customFields; 36 if (customFields && typeof customFields === 'object' && !Array.isArray(customFields)) { 37 return customFields[PRODUCT_SUPPLIER_FIELD_KEY]; 38 } 39 const customValues = values.customValues; 40 if (customValues && typeof customValues === 'object' && !Array.isArray(customValues)) { 41 return customValues[PRODUCT_SUPPLIER_FIELD_KEY]; 42 } 43 return undefined; 44} 45function normalizeProductSupplierId(value) { 46 if (value === PRODUCT_SUPPLIER_NONE_VALUE || value === '' || value == null) return null; 47 if (!isCompanyId(value)) return null; 48 return value; 49} 50function encodeProductSupplierHeader(value) { 51 return normalizeProductSupplierId(value) ?? ''; 52} 53function readHeaderValue(headers, name) { 54 const target = name.toLowerCase(); 55 for (const [key, value] of Object.entries(headers)){ 56 if (key.toLowerCase() === target) return value; 57 } 58 return undefined; 59} 60function mergeSupplierIntoProductBody(body, supplierId) { 61 const next = { 62 ...body ?? {} 63 }; 64 const existing = next.customFields; 65 const customFields = existing && typeof existing === 'object' && !Array.isArray(existing) ? { 66 ...existing 67 } : {}; 68 customFields[PRODUCT_SUPPLIER_FIELD_KEY] = supplierId; 69 next.customFields = customFields; 70 return next; 71} 72function projectProductSupplierForSubmit(values) { 73 const supplierId = normalizeProductSupplierId(readProductSupplierValue(values)); 74 if (values[PRODUCT_SUPPLIER_SUBMIT_ALIAS] === supplierId) return values; 75 return { 76 ...values, 77 [PRODUCT_SUPPLIER_FIELD_ID]: supplierId ?? PRODUCT_SUPPLIER_NONE_VALUE, 78 [PRODUCT_SUPPLIER_SUBMIT_ALIAS]: supplierId 79 }; 80} 81__turbopack_context__.s([ 82 "PRODUCT_SUPPLIER_FIELD_ID", 83 0, 84 PRODUCT_SUPPLIER_FIELD_ID, 85 "PRODUCT_SUPPLIER_HEADER", 86 0, 87 PRODUCT_SUPPLIER_HEADER, 88 "PRODUCT_SUPPLIER_NONE_VALUE", 89 0, 90 PRODUCT_SUPPLIER_NONE_VALUE, 91 "PRODUCT_SUPPLIER_OPTIONS_PATH", 92 0, 93 PRODUCT_SUPPLIER_OPTIONS_PATH, 94 "encodeProductSupplierHeader", 95 0, 96 encodeProductSupplierHeader, 97 "isCompanyId", 98 0, 99 isCompanyId, 100 "normalizeProductSupplierId", 101 0, 102 normalizeProductSupplierId, 103 "projectProductSupplierForSubmit", 104 0, 105 projectProductSupplierForSubmit, 106 "readProductSupplierValue", 107 0, 108 readProductSupplierValue 109]); 110}), 111450546, ((__turbopack_context__) => { 112"use strict"; 113 114const GENIKOS_DEFAULT_CURRENCY = 'EUR'; 115function hasExplicitCurrency(input, field) { 116 const value = input[field]; 117 return typeof value === 'string' && value.trim().length > 0; 118} 119function applyDefaultCurrency(input, field, defaultCurrency = GENIKOS_DEFAULT_CURRENCY) { 120 if (hasExplicitCurrency(input, field)) return null; 121 return { 122 [field]: defaultCurrency 123 }; 124} 125__turbopack_context__.s([ 126 "GENIKOS_DEFAULT_CURRENCY", 127 0, 128 GENIKOS_DEFAULT_CURRENCY 129]); 130}), 131321208, ((__turbopack_context__) => { 132"use strict"; 133 134var __TURBOPACK__imported__module__843476__ = __turbopack_context__.i(843476); 135var __TURBOPACK__imported__module__271645__ = __turbopack_context__.i(271645); 136var __TURBOPACK__imported__module__928441__ = __turbopack_context__.i(928441); 137var __TURBOPACK__imported__module__484973__ = __turbopack_context__.i(484973); 138var __TURBOPACK__imported__module__341881__ = __turbopack_context__.i(341881); 139var __TURBOPACK__imported__module__631465__ = __turbopack_context__.i(631465); 140'use client'; 141; 142; 143; 144; 145; 146; 147function toOption(row) { 148 return { 149 id: String(row.id), 150 name: row.name || '', 151 projectCode: row.project_code || null, 152 status: row.status || null, 153 companyName: row.company_name || null 154 }; 155} 156function optionLabel(option) { 157 const code = option.projectCode?.trim(); 158 return [ 159 option.name || code || option.id.slice(0, 8), 160 code
161 ].filter(Boolean).join(' · '); 162} 163function optionDescription(option) { 164 const parts = [ 165 option.status, 166 option.companyName 167 ].filter(Boolean); 168 return parts.length ? parts.join(' · ') : null; 169} 170function ProjectSelect({ value, onChange, disabled = false, placeholder }) { 171 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 172 const optionsByIdRef = __TURBOPACK__imported__module__271645__["useRef"](new Map()); 173 const loadSuggestions = __TURBOPACK__imported__module__271645__["useCallback"](async (query)=>{ 174 try { 175 const params = { 176 page: '1', 177 pageSize: '25', 178 sortField: 'created_at', 179 sortDir: 'desc' 180 }; 181 if (query && query.trim()) params.search = query.trim(); 182 const response = await (0, __TURBOPACK__imported__module__631465__["fetchCrudList"])('genikos_projects/projects', params); 183 return (response.items ?? []).map((row)=>{ 184 const option = toOption(row); 185 optionsByIdRef.current.set(option.id, option); 186 return { 187 value: option.id, 188 label: optionLabel(option), 189 description: optionDescription(option) 190 }; 191 }); 192 } catch { 193 (0, __TURBOPACK__imported__module__484973__["flash"])(t('genikos_projects.select.loadError', 'Failed to load projects.'), 'error'); 194 return []; 195 } 196 }, [ 197 t 198 ]); 199 const resolveLabel = __TURBOPACK__imported__module__271645__["useCallback"](async (id)=>{ 200 const cached = optionsByIdRef.current.get(id); 201 if (cached) return optionLabel(cached); 202 try { 203 const response = await (0, __TURBOPACK__imported__module__631465__["fetchCrudList"])('genikos_projects/projects', { 204 page: '1', 205 pageSize: '1', 206 id 207 }); 208 const row = response.items?.[0]; 209 if (!row) return id; 210 const option = toOption(row); 211 optionsByIdRef.current.set(option.id, option); 212 return optionLabel(option); 213 } catch { 214 return id; 215 } 216 }, []); 217 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__341881__["ComboboxInput"], { 218 value: value ?? '', 219 onChange: (next)=>{ 220 const trimmed = next.trim(); 221 if (!trimmed) { 222 onChange(null); 223 return; 224 } 225 onChange(optionsByIdRef.current.get(trimmed) ?? { 226 id: trimmed, 227 name: '', 228 projectCode: null, 229 status: null, 230 companyName: null 231 }); 232 }, 233 loadSuggestions: loadSuggestions, 234 resolveLabel: resolveLabel, 235 allowCustomValues: false, 236 clearable: true, 237 disabled: disabled, 238 placeholder: placeholder ?? t('genikos_projects.select.placeholder', 'Search projectsâ¦'), 239 clearLabel: t('genikos_projects.select.clear', 'Clear selection') 240 }); 241} 242__turbopack_context__.s([ 243 "ProjectSelect", 244 0, 245 ProjectSelect 246]); 247}), 248655021, ((__turbopack_context__) => { 249"use strict"; 250 251const GENIKOS_EXPENSE_ENTITY_ID = 'genikos_expenses:genikos_expense'; 252const EXPENSE_STATUSES = [ 253 'draft', 254 'submitted', 255 'approved', 256 'paid', 257 'cancelled' 258]; 259const EXPENSE_STATUS_LABELS = { 260 draft: 'Draft', 261 submitted: 'Submitted', 262 approved: 'Approved', 263 paid: 'Paid', 264 cancelled: 'Cancelled' 265}; 266function isExpenseStatus(value) { 267 return EXPENSE_STATUSES.includes(value); 268} 269const EXPENSE_PAYMENT_METHODS = [ 270 'cash', 271 'card', 272 'bank_transfer', 273 'direct_debit', 274 'paypal', 275 'other' 276]; 277const EXPENSE_PAYMENT_METHOD_LABELS = { 278 cash: 'Cash', 279 card: 'Card', 280 bank_transfer: 'Bank transfer', 281 direct_debit: 'Direct debit', 282 paypal: 'PayPal', 283 other: 'Other' 284}; 285function isExpensePaymentMethod(value) { 286 return EXPENSE_PAYMENT_METHODS.includes(value); 287} 288const EXPENSE_CATEGORIES = [ 289 'travel_accommodation', 290 'meals_entertainment', 291 'vehicle_fuel', 292 'office_supplies', 293 'software_subscriptions', 294 'professional_fees', 295 'utilities_telecom', 296 'rent_facilities', 297 'marketing_advertising', 298 'equipment_maintenance', 299 'other' 300]; 301const EXPENSE_CATEGORY_LABELS = { 302 travel_accommodation: 'Travel accommodation', 303 meals_entertainment: 'Meals entertainment', 304 vehicle_fuel: 'Vehicle fuel', 305 office_supplies: 'Office supplies', 306 software_subscriptions: 'Software subscriptions', 307 professional_fees: 'Professional fees', 308 utilities_telecom: 'Utilities telecom', 309 rent_facilities: 'Rent facilities', 310 marketing_advertising: 'Marketing advertising', 311 equipment_maintenance: 'Equipment maintenance', 312 other: 'Other' 313}; 314function isExpenseCategory(value) { 315 return EXPENSE_CATEGORIES.includes(value); 316} 317function formatExpenseAmount(amount, currency, locale) { 318 if (amount == null || Number.isNaN(amount)) return ''; 319 const code = typeof currency === 'string' && currency.trim() ? currency.trim().toUpperCase() : ''; 320 const localeTag = locale === 'de' ? 'de-DE' : locale === 'es' ? 'es-ES' : locale === 'pl' ? 'pl-PL' : locale === 'en' ? 'en-US' : locale?.trim() || 'en-US'; 321 try { 322 if (code) { 323 return new Intl.NumberFormat(localeTag, { 324 style: 'currency', 325 currency: code, 326 maximumFractionDigits: 2 327 }).format(amount); 328 } 329 } catch { 330 // fall through to plain number 331 } 332 try {
333 return code ? `${amount.toLocaleString(localeTag)} ${code}` : amount.toLocaleString(localeTag); 334 } catch { 335 return code ? `${amount} ${code}` : String(amount); 336 } 337} 338__turbopack_context__.s([ 339 "EXPENSE_CATEGORIES", 340 0, 341 EXPENSE_CATEGORIES, 342 "EXPENSE_CATEGORY_LABELS", 343 0, 344 EXPENSE_CATEGORY_LABELS, 345 "EXPENSE_PAYMENT_METHODS", 346 0, 347 EXPENSE_PAYMENT_METHODS, 348 "EXPENSE_PAYMENT_METHOD_LABELS", 349 0, 350 EXPENSE_PAYMENT_METHOD_LABELS, 351 "GENIKOS_EXPENSE_ENTITY_ID", 352 0, 353 GENIKOS_EXPENSE_ENTITY_ID, 354 "formatExpenseAmount", 355 0, 356 formatExpenseAmount, 357 "isExpenseCategory", 358 0, 359 isExpenseCategory, 360 "isExpensePaymentMethod", 361 0, 362 isExpensePaymentMethod 363]); 364}), 365501545, ((__turbopack_context__) => { 366"use strict"; 367 368var __TURBOPACK__imported__module__655021__ = __turbopack_context__.i(655021); 369; 370; 371function expensePaymentMethodLabel(method, translate) { 372 if (!method) return 'â'; 373 const fallback = (0, __TURBOPACK__imported__module__655021__["isExpensePaymentMethod"])(method) ? __TURBOPACK__imported__module__655021__["EXPENSE_PAYMENT_METHOD_LABELS"][method] : method; 374 return translate ? translate(`genikos_expenses.paymentMethod.${method}`, fallback) : fallback; 375} 376__turbopack_context__.s([ 377 "expensePaymentMethodLabel", 378 0, 379 expensePaymentMethodLabel 380]); 381}), 382119194, ((__turbopack_context__) => { 383"use strict"; 384 385/** 386 * @license lucide-react v1.24.0 - ISC 387 * 388 * This source code is licensed under the ISC license. 389 * See the LICENSE file in the root directory of this source tree. 390 */ var __TURBOPACK__imported__module__456420__ = __turbopack_context__.i(456420); 391; 392const __iconNode = [ 393 [ 394 "path", 395 { 396 d: "M3 7V5a2 2 0 0 1 2-2h2", 397 key: "aa7l1z" 398 } 399 ], 400 [ 401 "path", 402 { 403 d: "M17 3h2a2 2 0 0 1 2 2v2", 404 key: "4qcy5o" 405 } 406 ], 407 [ 408 "path", 409 { 410 d: "M21 17v2a2 2 0 0 1-2 2h-2", 411 key: "6vwrx8" 412 } 413 ], 414 [ 415 "path", 416 { 417 d: "M7 21H5a2 2 0 0 1-2-2v-2", 418 key: "ioqczr" 419 } 420 ], 421 [ 422 "path", 423 { 424 d: "M7 12h10", 425 key: "b7w52i" 426 } 427 ] 428]; 429const ScanLine = (0, __TURBOPACK__imported__module__456420__["default"])("scan-line", __iconNode); 430; 431__turbopack_context__.s([ 432 "default", 433 0, 434 ScanLine 435]); 436}), 437259083, 420861, 438844863, 439987530, 440368909, 441732673, 442599678, 443445271, 444447654, 445((__turbopack_context__) => { 446"use strict"; 447 448// MERGED MODULE: [project]/src/modules/genikos_expenses/components/ExpenseCategoryPanel.tsx [app-client] (ecmascript) 449; 450var __TURBOPACK__imported__module__843476__ = __turbopack_context__.i(843476); 451var __TURBOPACK__imported__module__980799__ = __turbopack_context__.i(980799); 452var __TURBOPACK__imported__module__928441__ = __turbopack_context__.i(928441); 453var __TURBOPACK__imported__module__406911__ = __turbopack_context__.i(406911); 454var __TURBOPACK__imported__module__262524__ = __turbopack_context__.i(262524); 455var __TURBOPACK__imported__module__655021__ = __turbopack_context__.i(655021); 456// MERGED MODULE: [project]/src/modules/genikos_expenses/lib/expense-categories.ts [app-client] (ecmascript) <locals> 457; 458var __TURBOPACK__imported__module__655021__1 = __TURBOPACK__imported__module__655021__; 459; 460; 461function expenseCategoryLabel(category, translate) { 462 if (!category) return 'â'; 463 const fallback = (0, __TURBOPACK__imported__module__655021__1["isExpenseCategory"])(category) ? __TURBOPACK__imported__module__655021__1["EXPENSE_CATEGORY_LABELS"][category] : category; 464 return translate ? translate(`genikos_expenses.category.${category}`, fallback) : fallback; 465} 466function normalizeExpenseCategory(value) { 467 if (typeof value !== 'string') return null; 468 const trimmed = value.trim(); 469 if (!trimmed) return null; 470 const normalized = trimmed.toLowerCase().replace(/[\s/-]+/g, '_'); 471 if ((0, __TURBOPACK__imported__module__655021__1["isExpenseCategory"])(normalized)) return normalized; 472 const compact = normalized.replace(/_/g, ''); 473 const aliases = { 474 travel: 'travel_accommodation', 475 accommodation: 'travel_accommodation', 476 hotel: 'travel_accommodation', 477 lodging: 'travel_accommodation', 478 meals: 'meals_entertainment', 479 meal: 'meals_entertainment', 480 entertainment: 'meals_entertainment', 481 food: 'meals_entertainment', 482 restaurant: 'meals_entertainment', 483 fuel: 'vehicle_fuel', 484 petrol: 'vehicle_fuel', 485 gas: 'vehicle_fuel', 486 vehicle: 'vehicle_fuel', 487 office: 'office_supplies', 488 supplies: 'office_supplies', 489 software: 'software_subscriptions', 490 subscription: 'software_subscriptions', 491 subscriptions: 'software_subscriptions', 492 saas: 'software_subscriptions', 493 fees: 'professional_fees', 494 professional: 'professional_fees', 495 consulting: 'professional_fees', 496 legal: 'professional_fees', 497 utilities: 'utilities_telecom', 498 telecom: 'utilities_telecom', 499 telephone: 'utilities_telecom', 500 internet: 'utilities_telecom', 501 rent: 'rent_facilities', 502 facilities: 'rent_facilities', 503 facility: 'rent_facilities', 504 marketing: 'marketing_advertising', 505 advertising: 'marketing_advertising', 506 ads: 'marketing_advertising', 507 equipment: 'equipment_maintenance', 508 maintenance: 'equipment_maintenance', 509 repair: 'equipment_maintenance' 510 }; 511 if (aliases[normalized]) return aliases[normalized]; 512 if (aliases[compact]) return aliases[compact]; 513 for (const category of __TURBOPACK__imported__module__655021__1["EXPENSE_CATEGORIES"]){ 514 const labelCompact = __TURBOPACK__imported__module__655021__1["EXPENSE_CATEGORY_LABELS"][category].toLowerCase().replace(/[\s/-]+/g, ''); 515 if (compact === labelCompact || compact.includes(labelCompact) || labelCompact.includes(compact)) { 516 return category; 517 } 518 } 519 return 'other'; 520} 521__turbopack_context__.s([ 522 "expenseCategoryLabel", 523 0, 524 expenseCategoryLabel, 525 "normalizeExpenseCategory", 526 0, 527 normalizeExpenseCategory 528], 420861); 529'use client'; 530; 531; 532; 533; 534; 535; 536function ExpenseCategoryPanel({ category, onCategoryChange, className }) { 537 const t = (0, __TURBOPACK__imported__module__928441__["useT"])(); 538 const selected = (0, __TURBOPACK__imported__module__655021__["isExpenseCategory"])(category) ? category : undefined; 539 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 540 className: (0, __TURBOPACK__imported__module__406911__["cn"])('flex h-full flex-col rounded-lg border bg-card p-4', className), 541 children: [ 542 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsxs"])("p", { 543 className: "flex items-center gap-2 text-xs uppercase tracking-wide text-muted-foreground", 544 children: [ 545 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__980799__["Tag"], { 546 "aria-hidden": true, 547 className: "h-3.5 w-3.5" 548 }), 549 t('genikos_expenses.form.fields.category', 'Category') 550 ] 551 }), 552 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsxs"])("div", { 553 className: "mt-3 space-y-1", 554 children: [ 555 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsxs"])(__TURBOPACK__imported__module__262524__["Select"], { 556 value: selected, 557 onValueChange: (next)=>onCategoryChange(next ?? ''), 558 children: [ 559 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectTrigger"], { 560 className: "w-full", 561 "aria-label": t('genikos_expenses.form.fields.category', 'Category'), 562 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectValue"], { 563 placeholder: t('genikos_expenses.document.categoryPlaceholder', 'Select a category'), 564 children: selected ? expenseCategoryLabel(selected, (key, fallback)=>t(key, fallback)) : undefined 565 }) 566 }), 567 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectContent"], { 568 children: __TURBOPACK__imported__module__655021__["EXPENSE_CATEGORIES"].map((option)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])(__TURBOPACK__imported__module__262524__["SelectItem"], { 569 value: option, 570 children: expenseCategoryLabel(option, (key, fallback)=>t(key, fallback)) 571 }, option)) 572 }) 573 ] 574 }), 575 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__["jsx"])("p", { 576 className: "text-xs text-muted-foreground", 577 children: t('genikos_expenses.document.categoryHint', 'Applies to the whole expense, not individual lines.') 578 }) 579 ] 580 }) 581 ] 582 }); 583} 584__turbopack_context__.s([ 585 "ExpenseCategoryPanel", 586 0, 587 ExpenseCategoryPanel 588], 259083); 589// MERGED MODULE: [project]/src/modules/genikos_expenses/components/ExpenseVendorPanel.tsx [app-client] (ecmascript) 590; 591var __TURBOPACK__imported__module__843476__1 = __TURBOPACK__imported__module__843476__; 592var __TURBOPACK__imported__module__271645__ = __turbopack_context__.i(271645); 593var __TURBOPACK__imported__module__146387__ = __turbopack_context__.i(146387); 594var __TURBOPACK__imported__module__689664__ = __turbopack_context__.i(689664); 595var __TURBOPACK__imported__module__716327__ = __turbopack_context__.i(716327); 596var __TURBOPACK__imported__module__96315__ = __turbopack_context__.i(96315); 597var __TURBOPACK__imported__module__575387__ = __turbopack_context__.i(575387); 598var __TURBOPACK__imported__module__928441__1 = __TURBOPACK__imported__module__928441__; 599var __TURBOPACK__imported__module__484973__ = __turbopack_context__.i(484973); 600var __TURBOPACK__imported__module__490746__ = __turbopack_context__.i(490746); 601var __TURBOPACK__imported__module__388528__ = __turbopack_context__.i(388528); 602var __TURBOPACK__imported__module__9762__ = __turbopack_context__.i(9762); 603var __TURBOPACK__imported__module__406911__1 = __TURBOPACK__imported__module__406911__; 604var __TURBOPACK__imported__module__162656__ = __turbopack_context__.i(162656); 605// MERGED MODULE: [project]/src/modules/genikos_expenses/lib/expense-vendor.ts [app-client] (ecmascript) 606; 607var __TURBOPACK__imported__module__162656__1 = __TURBOPACK__imported__module__162656__; 608; 609function emptyExpenseVendor() { 610 return { 611 companyId: null, 612 name: null, 613 email: null, 614 phone: null, 615 taxId: null, 616 companyNumber: null, 617 addressLines: [] 618 }; 619} 620function isExpenseVendorEmpty(vendor) { 621 if (!vendor) return true; 622 return !vendor.companyId && !vendor.name?.trim() && !vendor.email?.trim() && !vendor.phone?.trim() && !vendor.taxId?.trim() && !vendor.companyNumber?.trim() && !vendor.addressLines?.length; 623} 624function vendorAddressToLines(address) { 625 if (!address?.trim()) return []; 626 return address.split('\n').map((line)=>
626line.trim()).filter(Boolean); 627} 628function vendorLinesToAddress(lines) { 629 if (!lines?.length) return null; 630 const joined = lines.map((line)=>line.trim()).filter(Boolean).join('\n'); 631 return joined.length > 0 ? joined : null; 632} 633function readNonEmptyString(value) { 634 if (typeof value !== 'string') return null; 635 const trimmed = value.trim(); 636 return trimmed.length > 0 ? trimmed : null; 637} 638function vendorFromCompanyRecord(record) { 639 const companyId = (0, __TURBOPACK__imported__module__162656__1["isCompanyId"])(record.id) ? record.id : null; 640 const name = readNonEmptyString(record.display_name) ?? readNonEmptyString(record.displayName) ?? readNonEmptyString(record.legal_name) ?? readNonEmptyString(record.legalName) ?? readNonEmptyString(record.name); 641 const email = readNonEmptyString(record.primary_email) ?? readNonEmptyString(record.primaryEmail) ?? readNonEmptyString(record.email); 642 const phone = readNonEmptyString(record.primary_phone) ?? readNonEmptyString(record.primaryPhone) ?? readNonEmptyString(record.phone); 643 return { 644 companyId, 645 name, 646 email, 647 phone, 648 taxId: null, 649 companyNumber: null, 650 addressLines: [] 651 }; 652} 653function vendorFromStoredFields(input) { 654 return { 655 companyId: (0, __TURBOPACK__imported__module__162656__1["isCompanyId"])(input.vendorCompanyId) ? input.vendorCompanyId : null, 656 name: input.vendorName?.trim() || null, 657 email: input.vendorEmail?.trim() || null, 658 phone: input.vendorPhone?.trim() || null, 659 taxId: input.vendorTaxId?.trim() || null, 660 companyNumber: input.vendorCompanyNumber?.trim() || null, 661 addressLines: vendorAddressToLines(input.vendorAddress) 662 }; 663} 664function vendorToStoredFields(vendor) { 665 if (!vendor || isExpenseVendorEmpty(vendor)) { 666 return { 667 vendor_company_id: null, 668 vendor_name: null, 669 vendor_email: null, 670 vendor_phone: null, 671 vendor_tax_id: null, 672 vendor_company_number: null, 673 vendor_address: null 674 }; 675 } 676 return { 677 vendor_company_id: vendor.companyId, 678 vendor_name: vendor.name?.trim() || null, 679 vendor_email: vendor.email?.trim() || null, 680 vendor_phone: vendor.phone?.trim() || null, 681 vendor_tax_id: vendor.taxId?.trim() || null, 682 vendor_company_number: vendor.companyNumber?.trim() || null, 683 vendor_address: vendorLinesToAddress(vendor.addressLines) 684 }; 685} 686function matchSupplierOptionByName(options, name) { 687 const needle = name?.trim().toLowerCase(); 688 if (!needle) return null; 689 const matches = options.filter((option)=>option.label.trim().toLowerCase() === needle); 690 return matches.length === 1 ? matches[0] : null; 691} 692__turbopack_context__.s([ 693 "emptyExpenseVendor", 694 0, 695 emptyExpenseVendor, 696 "isExpenseVendorEmpty", 697 0, 698 isExpenseVendorEmpty, 699 "matchSupplierOptionByName", 700 0, 701 matchSupplierOptionByName, 702 "vendorFromCompanyRecord", 703 0, 704 vendorFromCompanyRecord, 705 "vendorFromStoredFields", 706 0, 707 vendorFromStoredFields, 708 "vendorToStoredFields", 709 0, 710 vendorToStoredFields 711], 844863); 712'use client'; 713; 714; 715; 716; 717; 718; 719; 720; 721; 722; 723; 724const SEARCH_DEBOUNCE_MS = 250; 725function asCompanyRecord(value) { 726 if (!value || typeof value !== 'object' || Array.isArray(value)) return null; 727 return value; 728} 729function matchesQuery(option, query) { 730 const normalized = query.trim().toLowerCase(); 731 if (!normalized) return true; 732 return option.label.toLowerCase().includes(normalized); 733} 734function ExpenseVendorPanel({ vendor, onVendorChange, disabled = false, className }) { 735 const t = (0, __TURBOPACK__imported__module__928441__1["useT"])(); 736 const searchRef = __TURBOPACK__imported__module__271645__["useRef"](null); 737 const attemptedNameRef = __TURBOPACK__imported__module__271645__["useRef"](null); 738 const [open, setOpen] = __TURBOPACK__imported__module__271645__["useState"](false); 739 const [query, setQuery] = __TURBOPACK__imported__module__271645__["useState"](''); 740 const [options, setOptions] = __TURBOPACK__imported__module__271645__["useState"]([]); 741 const [visibleOptions, setVisibleOptions] = __TURBOPACK__imported__module__271645__["useState"]([]); 742 const optionsRef = __TURBOPACK__imported__module__271645__["useRef"](options); 743 optionsRef.current = options;
744 const selectedId = vendor?.companyId ?? null; 745 const empty = isExpenseVendorEmpty(vendor); 746 const loadOptions = __TURBOPACK__imported__module__271645__["useCallback"](async (search)=>{ 747 const queryText = search?.trim() ?? ''; 748 const suffix = queryText ? `?q=${encodeURIComponent(queryText)}` : ''; 749 const call = await (0, __TURBOPACK__imported__module__490746__["apiCall"])(`${__TURBOPACK__imported__module__162656__["PRODUCT_SUPPLIER_OPTIONS_PATH"]}${suffix}`, undefined, { 750 fallback: { 751 items: [] 752 } 753 }); 754 const items = Array.isArray(call.result?.items) ? call.result.items : []; 755 return items.filter((item)=>Boolean(item) && typeof item.value === 'string' && typeof item.label === 'string'); 756 }, []); 757 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 758 let cancelled = false; 759 const load = async ()=>{ 760 try { 761 const items = await loadOptions(); 762 if (!cancelled) { 763 setOptions(items); 764 setVisibleOptions(items); 765 } 766 } catch { 767 if (!cancelled) { 768 setOptions([]); 769 setVisibleOptions([]); 770 (0, __TURBOPACK__imported__module__484973__["flash"])(t('genikos_expenses.vendor.loadError', 'Unable to load suppliers'), 'error'); 771 } 772 } 773 }; 774 void load(); 775 return ()=>{ 776 cancelled = true; 777 }; 778 }, [ 779 loadOptions, 780 t 781 ]); 782 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 783 if (!query.trim()) setVisibleOptions(options); 784 }, [ 785 options, 786 query 787 ]); 788 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 789 if (!open) return; 790 const queryText = query.trim(); 791 if (!queryText) return; 792 setVisibleOptions(optionsRef.current.filter((option)=>matchesQuery(option, queryText))); 793 let cancelled = false; 794 const handle = window.setTimeout(()=>{ 795 void loadOptions(queryText).then((items)=>{ 796 if (cancelled) return; 797 setVisibleOptions(items); 798 setOptions((current)=>{ 799 const byId = new Map(current.map((option)=>[ 800 option.value, 801 option 802 ])); 803 for (const item of items)byId.set(item.value, item); 804 return Array.from(byId.values()); 805 }); 806 }).catch(()=>{ 807 if (!cancelled) { 808 (0, __TURBOPACK__imported__module__484973__["flash"])(t('genikos_expenses.vendor.loadError', 'Unable to load suppliers'), 'error'); 809 } 810 }); 811 }, SEARCH_DEBOUNCE_MS); 812 return ()=>{ 813 cancelled = true; 814 window.clearTimeout(handle); 815 }; 816 }, [ 817 loadOptions, 818 open, 819 query, 820 t 821 ]); 822 const applyCompanyId = __TURBOPACK__imported__module__271645__["useCallback"](async (companyId)=>{ 823 if (!companyId) { 824 onVendorChange(emptyExpenseVendor()); 825 return; 826 } 827 const call = await (0, __TURBOPACK__imported__module__490746__["apiCall"])(`/api/customers/companies?id=${encodeURIComponent(companyId)}&pageSize=1`, undefined, { 828 fallback: { 829 items: [] 830 } 831 }); 832 const record = asCompanyRecord(Array.isArray(call.result?.items) ? call.result.items[0] : null); 833 if (!record) { 834 const cached = options.find((option)=>option.value === companyId); 835 onVendorChange({ 836 ...emptyExpenseVendor(), 837 companyId, 838 name: cached?.label ?? vendor?.name ?? null 839 }); 840 return; 841 } 842 onVendorChange(vendorFromCompanyRecord(record)); 843 }, [ 844 onVendorChange, 845 options, 846 vendor?.name 847 ]); 848 __TURBOPACK__imported__module__271645__["useEffect"](()=>{ 849 const name = vendor?.name?.trim() ?? ''; 850 if (vendor?.companyId || !name || attemptedNameRef.current === name) return; 851 attemptedNameRef.current = name; 852 const match = matchSupplierOptionByName(options, name); 853 if (match) void applyCompanyId(match.value); 854 }, [ 855 applyCompanyId, 856 options, 857 vendor?.companyId, 858 vendor?.name 859 ]); 860 const selectedLabel = __TURBOPACK__imported__module__271645__["useMemo"](()=>{ 861 if (!selectedId) return null; 862 const fromOptions = options.find((option)=>option.value === selectedId); 863 const label = fromOptions?.label ?? vendor?.name?.trim(); 864 return label && label.length > 0 ? label : selectedId; 865 }, [ 866 options, 867 selectedId, 868 vendor?.name 869 ]); 870 const noneLabel = t('genikos_expenses.vendor.none', 'Not set'); 871 const showNone = matchesQuery({ 872 value: '', 873 label: noneLabel 874 }, query); 875 const setOpenSafe = __TURBOPACK__imported__module__271645__["useCallback"]((next)=>{ 876 if (disabled) return; 877 setOpen(next); 878 if (!next) { 879 setQuery(''); 880 setVisibleOptions(options); 881 } 882 }, [ 883 disabled, 884 options 885 ]); 886 const selectCompany = __TURBOPACK__imported__module__271645__["useCallback"]((companyId)=>{ 887 setOpenSafe(false); 888 void applyCompanyId(companyId); 889 }, [ 890 applyCompanyId, 891 setOpenSafe 892 ]); 893 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("div", { 894 className: (0, __TURBOPACK__imported__module__406911__1["cn"])('flex h-full flex-col rounded-lg border bg-card p-4', className), 895 children: [ 896 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("p", { 897 className: "flex items-center gap-2 text-xs uppercase tracking-wide text-muted-foreground", 898 children: [ 899 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__146387__["Building2"], { 900 "aria-hidden": true, 901 className: "h-3.5 w-3.5" 902 }), 903 t('genikos_expenses.vendor.label', 'Company') 904 ] 905 }), 906 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("div", { 907 className: "mt-3 space-y-3", 908 children: [ 909 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])(__TURBOPACK__imported__module__388528__["Popover"], { 910 open: open, 911 onOpenChange: setOpenSafe, 912 children: [ 913 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__388528__["PopoverTrigger"], { 914 asChild: true, 915 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("button", { 916 type: "button", 917 role: "combobox", 918 "aria-expanded": open, 919 "aria-haspopup": "listbox", 920 "aria-label": t('genikos_expenses.vendor.label', 'Company'), 921 disabled: disabled, 922 className: (0, __TURBOPACK__imported__module__406911__1["cn"])('inline-flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-background px-3 text-sm shadow-xs transition-colors outline-none', 'hover:bg-muted/40 focu
922s-visible:border-foreground focus-visible:shadow-focus', 'disabled:cursor-not-allowed disabled:border-border-disabled disabled:bg-bg-disabled disabled:shadow-none disabled:hover:bg-bg-disabled'), 923 children: [ 924 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("span", { 925 className: (0, __TURBOPACK__imported__module__406911__1["cn"])('min-w-0 flex-1 truncate text-left', !selectedLabel && 'text-muted-foreground'), 926 children: selectedLabel ?? t('genikos_expenses.vendor.placeholder', 'Select a supplier') 927 }), 928 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__716327__["ChevronDown"], { 929 className: "size-4 shrink-0 text-muted-foreground", 930 "aria-hidden": "true" 931 }) 932 ] 933 }) 934 }), 935 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])(__TURBOPACK__imported__module__388528__["PopoverContent"], { 936 align: "start", 937 className: "w-[var(--radix-popover-trigger-width)] space-y-2 p-2", 938 onOpenAutoFocus: (event)=>{ 939 event.preventDefault(); 940 searchRef.current?.focus(); 941 }, 942 children: [ 943 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__9762__["SearchInput"], { 944 ref: searchRef, 945 size: "sm", 946 value: query, 947 onChange: setQuery, 948 placeholder: t('genikos_expenses.vendor.searchPlaceholder', 'Search suppliersâ¦'), 949 "aria-label": t('genikos_expenses.vendor.searchPlaceholder', 'Search suppliersâ¦'), 950 onKeyDown: (event)=>{ 951 if (event.key === 'Enter') event.preventDefault(); 952 } 953 }), 954 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("div", { 955 className: "max-h-48 overflow-y-auto", 956 role: "listbox", 957 children: [ 958 showNone ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("button", { 959 type: "button", 960 role: "option", 961 "aria-selected": !selectedId, 962 onClick: ()=>selectCompany(null), 963 className: "flex w-full cursor-pointer items-center gap-2 rounded-md p-2 text-left text-sm hover:bg-muted focus-visible:bg-muted focus-visible:outline-none", 964 children: [ 965 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("span", { 966 className: "min-w-0 flex-1 truncate", 967 children: noneLabel 968 }), 969 !selectedId ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__689664__["Check"], { 970 className: "size-4 shrink-0 text-foreground", 971 "aria-hidden": "true" 972 }) : null 973 ] 974 }) : null, 975 visibleOptions.map((option)=>{ 976 const isSelected = option.value === selectedId; 977 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("button", { 978 type: "button", 979 role: "option", 980 "aria-selected": isSelected, 981 onClick: ()=>selectCompany(option.value), 982 className: "flex w-full cursor-pointer items-center gap-2 rounded-md p-2 text-left text-sm hover:bg-muted focus-visible:bg-muted focus-visible:outline-none", 983 children: [ 984 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("span", { 985 className: "min-w-0 flex-1 truncate", 986 children: option.label 987 }), 988 isSelected ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__689664__["Check"], { 989 className: "size-4 shrink-0 text-foreground", 990 "aria-hidden": "true" 991 }) : null 992 ] 993 }, option.value); 994 }), 995 !showNone && visibleOptions.length === 0 ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("div", { 996 className: "px-2 py-3 text-sm text-muted-foreground", 997 children: t('genikos_expenses.vendor.empty', 'No matching suppliers') 998 }) : null 999 ] 1000 }) 1001 ] 1002 }) 1003 ] 1004 }), 1005 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("p", { 1006 className: "text-xs text-muted-foreground", 1007 children: t('genikos_expenses.vendor.hint', 'Choose a supplier company for this expense.') 1008 }), 1009 !vendor?.companyId && vendor?.name ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("p", { 1010 className: "text-xs text-muted-foreground", 1011 children: [ 1012 t('genikos_expenses.vendor.unlinkedHint', 'Scanned company is not linked yet. Select a matching supplier.'), 1013 ' ', 1014 vendor.name 1015 ] 1016 }) : null, 1017 !empty && vendor?.companyId ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("div", { 1018 className: "flex min-w-0 items-start gap-3", 1019 children: [ 1020 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("div", { 1021 className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-muted", 1022 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__146387__["Building2"], { 1023 "aria-hidden": true, 1024 className: "h-5 w-5 text-muted-foreground" 1025 }) 1026 }), 1027 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("div", { 1028 className: "min-w-0 space-y-1", 1029 children: [ 1030 vendor.name ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("p", { 1031 className: "text-sm font-medium leading-tight text-foreground", 1032 children: vendor.name 1033 }) : null, 1034 vendor.email ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("p", { 1035 className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", 1036 children: [ 1037 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__96315__["Mail"], { 1038 className: "h-3.5 w-3.5 shrink-0", 1039 "aria-hidden": true 1040 }), 1041 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("span", { 1042 className: "truncate", 1043 title: vendor.email, 1044 children: vendor.email 1045 }) 1046 ] 1047 }) : null, 1048 vendor.phone ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsxs"])("p", { 1049 className: "flex min-w-0 items-center gap-1 text-xs text-muted-foreground", 1050 children: [ 1051 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])(__TURBOPACK__imported__module__575387__["Phone"], { 1052 className: "h-3.5 w-3.5 shrink-0", 1053 "aria-hidden": true 1054 }), 1055 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__1["jsx"])("span", { 1056 className: "truncate", 1057 children: vendor.phone 1058 }) 1059 ] 1060 }) : null 1061 ] 1062 }) 1063 ] 1064 }) : null 1065 ] 1066 }) 1067 ] 1068 }); 1069} 1070__turbopack_context__.s([ 1071 "ExpenseVendorPanel", 1072 0, 1073 ExpenseVendorPanel 1074], 987530); 1075// MERGED MODULE: [project]/src/modules/genikos_expenses/components/ExpenseDocumentTotals.tsx [app-client] (ecmascript) 1076; 1077var __TURBOPACK__imported__module__843476__2 = __TURBOPACK__imported__module__843476__; 1078var __TURBOPACK__imported__module__406911__2 = __TURBOPACK__imported__module__406911__; 1079var __TURBOPACK__imported__module__928441__2 = __TURBOPACK__imported__module__928441__; 1080var __TURBOPACK__imported__module__655021__2 = __TURBOPACK__imported__module__655021__; 1081'use client'; 1082; 1083; 1084; 1085; 1086function formatTotalsAmount(amount, currency, locale) { 1087 if (amount === null || amount === undefined) return 'â'; 1088 const parsed = typeof amount === 'string' ? Number(amount) : amount; 1089 if (Number.isNaN(parsed)) return 'â'; 1090 return (0, __TURBOPACK__imported__module__655021__2["formatExpenseAmount"])(parsed, currency, locale) || 'â'; 1091} 1092function ExpenseDocumentTotals({ title, currency, items, className }) { 1093 const t = (0, __TURBOPACK__imported__module__928441__2["useT"])(); 1094 const locale = (0, __TURBOPACK__imported__module__928441__2["useLocale"])(); 1095 const heading = title ?? t('genikos_expenses.document.totals.title', 'Totals'); 1096 if (!items.length) return null; 1097 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("div", { 1098 className: (0, __TURBOPACK__imported__module__406911__2["cn"])('space-y-3', className), 1099 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsxs"])("div", { 1100 className: "overflow-hidden rounded-xl border bg-card shadow-sm", 1101 children: [ 1102 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsxs"])("div", { 1103 className: "flex items-center justify-between border-b bg-muted/50 px-4 py-3", 1104 children: [ 1105 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("span", { 1106 className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", 1107 children: heading 1108 }), 1109 currency ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("span", { 1110 className: "rounded-full border border-border/70 bg-background/80 px-3 py-1 text-xs font-semibold tracking-wide text-foreground", 1111 children: currency 1112 }) : null 1113 ] 1114 }), 1115 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsxs"])("table", { 1116 className: "w-full text-sm", 1117 children: [ 1118 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("tbody", { 1119 className: "divide-y divide-border/80", 1120 children: items.filter((item)=>!item.emphasize).map((item)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsxs"])("tr", { 1121 className: "bg-background/80 transition-colors hover:bg-muted/30", 1122 children: [ 1123 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("td", { 1124 className: "px-4 py-3 font-medium text-foreground
1124/90", 1125 children: item.label 1126 }), 1127 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("td", { 1128 className: "px-4 py-3 text-right", 1129 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("span", { 1130 className: "font-mono text-base text-foreground", 1131 children: formatTotalsAmount(item.amount, currency, locale) 1132 }) 1133 }) 1134 ] 1135 }, item.key)) 1136 }), 1137 items.some((item)=>item.emphasize) ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("tfoot", { 1138 className: "border-t-2 border-primary/40 bg-primary/5", 1139 children: items.filter((item)=>item.emphasize).map((item)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsxs"])("tr", { 1140 children: [ 1141 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("td", { 1142 className: "px-4 py-3 font-semibold uppercase tracking-wide text-foreground", 1143 children: item.label 1144 }), 1145 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("td", { 1146 className: "px-4 py-3 text-right", 1147 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__2["jsx"])("span", { 1148 className: "font-mono text-lg font-semibold text-foreground", 1149 children: formatTotalsAmount(item.amount, currency, locale) 1150 }) 1151 }) 1152 ] 1153 }, item.key)) 1154 }) : null 1155 ] 1156 }) 1157 ] 1158 }) 1159 }); 1160} 1161__turbopack_context__.s([ 1162 "ExpenseDocumentTotals", 1163 0, 1164 ExpenseDocumentTotals 1165], 368909); 1166// MERGED MODULE: [project]/src/modules/genikos_expenses/components/ExpenseEditableLinesTable.tsx [app-client] (ecmascript) 1167; 1168var __TURBOPACK__imported__module__843476__3 = __TURBOPACK__imported__module__843476__; 1169var __TURBOPACK__imported__module__271645__1 = __TURBOPACK__imported__module__271645__; 1170var __TURBOPACK__imported__module__263676__ = __turbopack_context__.i(263676); 1171var __TURBOPACK__imported__module__110035__ = __turbopack_context__.i(110035); 1172var __TURBOPACK__imported__module__987030__ = __turbopack_context__.i(987030); 1173var __TURBOPACK__imported__module__262524__1 = __TURBOPACK__imported__module__262524__; 1174var __TURBOPACK__imported__module__928441__3 = __TURBOPACK__imported__module__928441__; 1175// MERGED MODULE: [project]/src/modules/genikos_expenses/lib/expense-lines.ts [app-client] (ecmascript) 1176; 1177; 1178function roundMoney(value, digits = 4) { 1179 if (!Number.isFinite(value)) return 0; 1180 const factor = 10 ** digits; 1181 return Math.round(value * factor) / factor; 1182} 1183function toFiniteNumber(value) { 1184 if (typeof value === 'number' && Number.isFinite(value)) return value; 1185 if (typeof value === 'string' && value.trim().length) { 1186 const parsed = Number(value); 1187 if (Number.isFinite(parsed)) return parsed; 1188 } 1189 return 0; 1190} 1191function computeExpenseLineAmounts(input) { 1192 const quantity = Math.max(0, toFiniteNumber(input.quantity)); 1193 const unitPriceNet = Math.max(0, toFiniteNumber(input.unitPriceNet)); 1194 const taxRate = Math.max(0, toFiniteNumber(input.taxRate)); 1195 const lineNet = roundMoney(quantity * unitPriceNet); 1196 const taxAmount = roundMoney(lineNet * (taxRate / 100)); 1197 const lineGross = roundMoney(lineNet + taxAmount); 1198 return { 1199 quantity: roundMoney(quantity), 1200 unitPriceNet: roundMoney(unitPriceNet), 1201 taxRate: roundMoney(taxRate), 1202 lineNet, 1203 taxAmount, 1204 lineGross 1205 }; 1206} 1207function computeExpenseDocument(lines) { 1208 const computedLines = lines.map((line)=>computeExpenseLineAmounts({ 1209 quantity: line.quantity, 1210 unitPriceNet: line.unitPriceNet, 1211 taxRate: line.taxRate 1212 })); 1213 let subtotalNet = 0; 1214 let taxTotal = 0; 1215 let grandTotalGross = 0; 1216 for (const line of computedLines){ 1217 subtotalNet += line.lineNet; 1218 taxTotal += line.taxAmount; 1219 grandTotalGross += line.lineGross; 1220 } 1221 return { 1222 lines: computedLines, 1223 totals: { 1224 subtotalNet: roundMoney(subtotalNet, 2), 1225 taxTotal: roundMoney(taxTotal, 2), 1226 grandTotalGross: roundMoney(grandTotalGross, 2) 1227 } 1228 }; 1229} 1230function createEmptyExpenseDraftLine(key) { 1231 return { 1232 key: key ?? `line-${Math.random().toString(36).slice(2, 10)}`, 1233 description: '', 1234 quantity: '1', 1235 unitPriceNet: '0', 1236 taxRate: '0', 1237 taxRateId: null 1238 }; 1239} 1240function parseExpenseNumber(value) { 1241 const trimmed = value.trim(); 1242 if (!trimmed.length) return Number.NaN; 1243 const normalized = trimmed.includes(',') && !trimmed.includes('.') ? trimmed.replace(',', '.') : trimmed.replace(/,/g, ''); 1244 const parsed = Number(normalized); 1245 return Number.isFinite(parsed) ? parsed : Number.NaN; 1246} 1247function isCompleteExpenseDraftLine(line) { 1248 const description = line.description.trim(); 1249 const quantity = parseExpenseNumber(line.quantity); 1250 const unitPriceNet = parseExpenseNumber(line.unitPriceNet); 1251 return description.length > 0 && Number.isFinite(quantity) && quantity > 0 && Number.isFinite(unitPriceNet) && unitPriceNet >= 0; 1252} 1253function resolveExpenseDocumentTitle(input) { 1254 const title = input.title?.trim(); 1255 if (title) return title; 1256 const category = input.category?.trim(); 1257 if (category) { 1258 const labeled = expenseCategoryLabel(category); 1259 return labeled === 'â' ? category : labeled; 1260 } 1261 for (const description of input.lineDescriptions ?? []){ 1262 const trimmed = description?.trim(); 1263 if (trimmed) return trimmed; 1264 } 1265 return ''; 1266} 1267function parseExpenseDraftNumber(value) { 1268 const parsed = parseExpenseNumber(value); 1269 return Number.isFinite(parsed) ? parsed : 0; 1270} 1271__turbopack_context__.s([ 1272 "computeExpenseDocument", 1273 0, 1274 computeExpenseDocument, 1275 "createEmptyExpenseDraftLine", 1276 0, 1277 createEmptyExpenseDraftLine, 1278 "isCompleteExpenseDraftLine", 1279 0, 1280 isCompleteExpenseDraftLine, 1281 "parseExpenseDraftNumber", 1282 0, 1283 parseExpenseDraftNumber, 1284 "resolveExpenseDocumentTitle", 1285 0, 1286 resolveExpenseDocumentTitle 1287], 732673); 1288// MERGED MODULE: [project]/src/modules/genikos_expenses/lib/tax-rates.ts [app-client] (ecmascript) 1289; 1290var __TURBOPACK__imported__module__490746__1 = __TURBOPACK__imported__module__490746__; 1291; 1292function resolveBooleanFlag(value) { 1293 if (typeof value === 'boolean') return value; 1294 if (typeof value === 'number') return value !== 0; 1295 if (typeof value === 'string') { 1296 const normalized = value.trim().toLowerCase(); 1297 return normalized === 'true' || normalized === '1' || normalized === 'yes'; 1298 } 1299 return false;
1300} 1301function mapTaxRateOption(item) { 1302 const id = typeof item.id === 'string' ? item.id : null; 1303 if (!id) return null; 1304 const rawRate = typeof item.rate === 'number' ? item.rate : Number(item.rate ?? Number.NaN); 1305 const name = typeof item.name === 'string' && item.name.trim().length ? item.name.trim() : id; 1306 const code = typeof item.code === 'string' && item.code.trim().length ? item.code.trim() : null; 1307 return { 1308 id, 1309 name, 1310 code, 1311 rate: Number.isFinite(rawRate) ? rawRate : null, 1312 isDefault: resolveBooleanFlag(typeof item.isDefault !== 'undefined' ? item.isDefault : item.is_default) 1313 }; 1314} 1315function formatTaxRateLabel(option) { 1316 const parts = [ 1317 option.name 1318 ]; 1319 if (option.code) parts.push(option.code.toUpperCase()); 1320 if (option.rate != null && Number.isFinite(option.rate)) parts.push(`${option.rate}%`); 1321 return parts.join(' ⢠'); 1322} 1323function findTaxRateIdByValue(taxRates, rate) { 1324 if (rate == null || !Number.isFinite(rate)) return null; 1325 const exact = taxRates.find((option)=>option.rate === rate); 1326 if (exact) return exact.id; 1327 const rounded = taxRates.find((option)=>option.rate != null && Math.abs(option.rate - rate) < 0.0001); 1328 return rounded?.id ?? null; 1329} 1330async function loadExpenseTaxRates() { 1331 const response = await (0, __TURBOPACK__imported__module__490746__1["apiCall"])('/api/sales/tax-rates?pageSize=100', undefined, { 1332 fallback: { 1333 items: [] 1334 } 1335 }); 1336 const items = Array.isArray(response.result?.items) ? response.result.items : []; 1337 return items.map((item)=>mapTaxRateOption(item)).filter((entry)=>Boolean(entry)); 1338} 1339__turbopack_context__.s([ 1340 "findTaxRateIdByValue", 1341 0, 1342 findTaxRateIdByValue, 1343 "formatTaxRateLabel", 1344 0, 1345 formatTaxRateLabel, 1346 "loadExpenseTaxRates", 1347 0, 1348 loadExpenseTaxRates 1349], 599678); 1350var __TURBOPACK__imported__module__655021__3 = __TURBOPACK__imported__module__655021__; 1351'use client'; 1352; 1353; 1354; 1355; 1356; 1357; 1358; 1359; 1360; 1361; 1362function updateLine(lines, key, patch) { 1363 return lines.map((line)=>line.key === key ? { 1364 ...line, 1365 ...patch 1366 } : line); 1367} 1368function ExpenseEditableLinesTable({ lines, onChange, currencyCode, onAddRow }) { 1369 const t = (0, __TURBOPACK__imported__module__928441__3["useT"])(); 1370 const locale = (0, __TURBOPACK__imported__module__928441__3["useLocale"])(); 1371 const [taxRates, setTaxRates] = __TURBOPACK__imported__module__271645__1["useState"]([]); 1372 __TURBOPACK__imported__module__271645__1["useEffect"](()=>{ 1373 let cancelled = false; 1374 void (async ()=>{ 1375 try { 1376 const options = await loadExpenseTaxRates(); 1377 if (!cancelled) setTaxRates(options); 1378 } catch { 1379 if (!cancelled) setTaxRates([]); 1380 } 1381 })(); 1382 return ()=>{ 1383 cancelled = true; 1384 }; 1385 }, []); 1386 const taxRateMap = __TURBOPACK__imported__module__271645__1["useMemo"](()=>{ 1387 const map = new Map(); 1388 for (const rate of taxRates)map.set(rate.id, rate); 1389 return map; 1390 }, [ 1391 taxRates 1392 ]); 1393 const computed = __TURBOPACK__imported__module__271645__1["useMemo"](()=>computeExpenseDocument(lines.map((line)=>({ 1394 description: line.description, 1395 quantity: Number(line.quantity) || 0, 1396 unitPriceNet: Number(line.unitPriceNet) || 0, 1397 taxRate: Number(line.taxRate) || 0 1398 }))), [ 1399 lines 1400 ]); 1401 const handleRemove = __TURBOPACK__imported__module__271645__1["useCallback"]((key)=>{ 1402 onChange((prev)=>{ 1403 const next = prev.filter((line)=>line.key !== key); 1404 return next.length ? next : [ 1405 createEmptyExpenseDraftLine() 1406 ]; 1407 }); 1408 }, [ 1409 onChange 1410 ]); 1411 const patchField = __TURBOPACK__imported__module__271645__1["useCallback"]((key, patch)=>{ 1412 onChange((prev)=>updateLine(prev, key, patch)); 1413 }, [ 1414 onChange 1415 ]); 1416 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])("div", { 1417 className: "space-y-3", 1418 children: [ 1419 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("div", { 1420 className: "overflow-visible rounded-xl border bg-card shadow-sm", 1421 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("div", { 1422 className: "overflow-visible", 1423 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])("table", { 1424 className: "w-full table-fixed text-sm", 1425 children: [ 1426 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])("colgroup", { 1427 children: [ 1428 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("col", {}), 1429 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("col", { 1430 style: { 1431 width: '7rem' 1432 } 1433 }), 1434 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("col", { 1435 style: { 1436 width: '9rem' 1437 } 1438 }), 1439 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("col", { 1440 style: { 1441 width: '13rem' 1442 } 1443 }), 1444 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("col", { 1445 style: { 1446 width: '9rem' 1447 } 1448 }), 1449 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("col", { 1450 style: { 1451 width: '3rem' 1452 } 1453 }) 1454 ] 1455 }), 1456 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("thead", { 1457 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])("tr", { 1458 className: "border-b bg-muted/50 text-left text-xs uppercase tracking-wide text-muted-foreground", 1459 children: [ 1460 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("th", { 1461 className: "px-4 py-3 font-semibold", 1462 children: t('genikos_expenses.document.lines.description', 'Description') 1463 }), 1464 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("th", { 1465 className: "px-4 py-3 font-semibold", 1466 children: t('genikos_expenses.document.lines.qty', 'Qty') 1467 }), 1468 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("th", { 1469 className: "px-4 py-3 font-semibold", 1470 children: t('genikos_expenses.document.lines.unitPrice', 'Unit price') 1471 }), 1472 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("th", { 1473 className: "px-4 py-3 font-semibold", 1474 children: t('genikos_expenses.document.lines.tax', 'Tax') 1475 }), 1476 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("th", { 1477 className: "px-4 py-3 font-semibold text-right", 1478 children: t('genikos_expenses.document.lines.total', 'Total') 1479 }), 1480 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("th", { 1481 className: "px-2 py-3 font-semibold text-right", 1482 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("span", { 1483 className: "sr-only", 1484 children: t('genikos_expenses.document.lines.remove', 'Remove line') 1485 }) 1486 }) 1487 ] 1488 }) 1489 }), 1490 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("tbody", { 1491 className: "divide-y divide-border/80", 1492 children: lines.map((line, index)=>{ 1493 const amount = computed.lines[index]?.lineGross ?? 0; 1494 const resolvedTaxRateId = line.taxRateId || findTaxRateIdByValue(taxRates, Number(line.taxRate)) || undefined; 1495 const selectedTax = resolvedTaxRateId ? taxRateMap.get(resolvedTaxRateId) ?? null : null; 1496 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])("tr", { 1497 className: "relative bg-background/80 focus-within:z-20", 1498 children: [ 1499 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("td", { 1500 className: "relative min-w-0 overflow-visible px-4 py-3 align-top", 1501 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__987030__["Input"], { 1502 value: line.description, 1503 onChange: (event)=>patchField(line.key, { 1504 description: event.target.value 1505 }), 1506 placeholder: t('genikos_expenses.document.lines.descriptionPlaceholder', 'What was purchased?'), 1507 maxLength: 500 1508 }) 1509 }), 1510 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("td", { 1511 className: "min-w-0 px-4 py-3 align-top", 1512 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__987030__["Input"], { 1513 type: "number", 1514 min: "0", 1515 step: "any", 1516 className: "w-full min-w-0", 1517 value: line.quantity, 1518 onChange: (event)=>patchField(line.key, { 1519 quantity: event.target.value 1520 }) 1521 }) 1522 }), 1523 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("td", { 1524 className: "min-w-0 px-4 py-3 align-top", 1525 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])("div", { 1526 className: "flex min-w-0 items-center gap-1", 1527 children: [ 1528 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__987030__["Input"], { 1529 type: "number", 1530 min: "0", 1531 step: "any", 1532 className: "min-w-0 flex-1", 1533 value: line.unitPriceNet, 1534 onChange: (event)=>patchField(line.key, { 1535 unitPriceNet: event.target.value 1536 }) 1537 }), 1538 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("span", { 1539 className: "shrink-0 text-xs text-muted-foreground", 1540 children: currencyCode 1541 }) 1542 ] 1543 }) 1544 }), 1545 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("td", { 1546 className: "min-w-0 px-4 py-3 align-top", 1547 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsxs"])(__TURBOPACK__imported__module__262524__1["Select"], { 1548 value: resolvedTaxRateId, 1549 onValueChange: (value)=>{ 1550 const nextId = value || null; 1551 if (!nextId) { 1552 patchField(line.key, { 1553 taxRateId: null, 1554 taxRate: '0' 1555 }); 1556 return; 1557 } 1558 const option = taxRateMap.get(nextId) ?? null; 1559 patchField(line.key, { 1560 taxRateId: nextId, 1561 taxRate: option?.rate != null && Number.isFinite(option.rate) ? String(option.rate) : '0' 1562 }); 1563 }, 1564 disabled: !taxRates.length, 1565 children: [ 1566 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__262524__1["SelectTrigger"], { 1567
1567 className: "w-full min-w-0", 1568 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__262524__1["SelectValue"], { 1569 placeholder: taxRates.length ? t('genikos_expenses.document.lines.taxNone', 'No tax') : t('genikos_expenses.document.lines.taxEmpty', 'No tax rates'), 1570 children: selectedTax ? formatTaxRateLabel(selectedTax) : undefined 1571 }) 1572 }), 1573 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__262524__1["SelectContent"], { 1574 children: taxRates.map((rate)=>/*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__262524__1["SelectItem"], { 1575 value: rate.id, 1576 children: formatTaxRateLabel(rate) 1577 }, rate.id)) 1578 }) 1579 ] 1580 }) 1581 }), 1582 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("td", { 1583 className: "min-w-0 px-4 py-3 align-middle text-right font-medium tabular-nums", 1584 children: (0, __TURBOPACK__imported__module__655021__3["formatExpenseAmount"])(amount, currencyCode, locale) || 'â' 1585 }), 1586 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("td", { 1587 className: "px-2 py-3 align-middle text-right", 1588 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__110035__["Button"], { 1589 type: "button", 1590 variant: "ghost", 1591 size: "icon", 1592 onClick: ()=>handleRemove(line.key), 1593 "aria-label": t('genikos_expenses.document.lines.remove', 'Remove line'), 1594 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__263676__["X"], { 1595 className: "h-4 w-4" 1596 }) 1597 }) 1598 }) 1599 ] 1600 }, line.key); 1601 }) 1602 }) 1603 ] 1604 }) 1605 }) 1606 }), 1607 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])("div", { 1608 className: "flex justify-start", 1609 children: /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__3["jsx"])(__TURBOPACK__imported__module__110035__["Button"], { 1610 type: "button", 1611 variant: "outline", 1612 size: "sm", 1613 onClick: onAddRow, 1614 children: t('genikos_expenses.document.lines.add', 'Add line') 1615 }) 1616 }) 1617 ] 1618 }); 1619} 1620__turbopack_context__.s([ 1621 "ExpenseEditableLinesTable", 1622 0, 1623 ExpenseEditableLinesTable 1624], 445271); 1625// MERGED MODULE: [project]/src/modules/genikos_expenses/components/ExpenseScanFromFileButton.tsx [app-client] (ecmascript) 1626; 1627var __TURBOPACK__imported__module__843476__4 = __TURBOPACK__imported__module__843476__; 1628var __TURBOPACK__imported__module__271645__2 = __TURBOPACK__imported__module__271645__; 1629// MERGED MODULE: [project]/node_modules/lucide-react/dist/esm/icons/scan-line.mjs [app-client] (ecmascript) <export default as ScanLine> 1630; 1631var __TURBOPACK__imported__module__119194__ = __turbopack_context__.i(119194); 1632var __TURBOPACK__imported__module__119194__ = __TURBOPACK__imported__module__119194__; 1633var __TURBOPACK__imported__module__632781__ = __turbopack_context__.i(632781); 1634var __TURBOPACK__imported__module__928441__4 = __TURBOPACK__imported__module__928441__; 1635var __TURBOPACK__imported__module__110035__1 = __TURBOPACK__imported__module__110035__; 1636var __TURBOPACK__imported__module__484973__1 = __TURBOPACK__imported__module__484973__; 1637'use client'; 1638; 1639; 1640; 1641; 1642; 1643; 1644const ACCEPT = '.pdf,image/png,image/jpeg,image/jpg,image/webp,image/gif,image/bmp,image/tiff'; 1645function ExpenseScanFromFileButton({ disabled = false, onExtracted }) { 1646 const t = (0, __TURBOPACK__imported__module__928441__4["useT"])(); 1647 const inputRef = __TURBOPACK__imported__module__271645__2["useRef"](null); 1648 const [scanning, setScanning] = __TURBOPACK__imported__module__271645__2["useState"](false); 1649 const handleFile = __TURBOPACK__imported__module__271645__2["useCallback"](async (file)=>{ 1650 if (!file) return; 1651 setScanning(true); 1652 try { 1653 const body = new FormData(); 1654 body.set('file', file); 1655 const response = await fetch('/api/genikos_expenses/extract-from-file', { 1656 method: 'POST', 1657 body, 1658 credentials: 'same-origin' 1659 }); 1660 const payload = await response.json().catch(()=>null); 1661 if (!response.ok || !payload?.draft) { 1662 const message = payload && typeof payload.error === 'string' && payload.error.trim() || t('genikos_expenses.scan.error.generic', 'Could not extract expense data from this file.'); 1663 (0, __TURBOPACK__imported__module__484973__1["flash"])(message, 'error'); 1664 return; 1665 } 1666 onExtracted(payload.draft, file); 1667 (0, __TURBOPACK__imported__module__484973__1["flash"])(t('genikos_expenses.scan.flash.success', 'Fields filled from the document. Review before saving.'), 'success'); 1668 } catch { 1669 (0, __TURBOPACK__imported__module__484973__1["flash"])(t('genikos_expenses.scan.error.generic', 'Could not extract expense data from this file.'), 'error'); 1670 } finally{ 1671 setScanning(false); 1672 if (inputRef.current) inputRef.current.value = ''; 1673 } 1674 }, [ 1675 onExtracted,
1676 t 1677 ]); 1678 return /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__4["jsxs"])(__TURBOPACK__imported__module__843476__4["Fragment"], { 1679 children: [ 1680 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__4["jsx"])("input", { 1681 ref: inputRef, 1682 type: "file", 1683 accept: ACCEPT, 1684 className: "hidden", 1685 onChange: (event)=>{ 1686 const file = event.target.files?.[0] ?? null; 1687 void handleFile(file); 1688 } 1689 }), 1690 /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__4["jsxs"])(__TURBOPACK__imported__module__110035__1["Button"], { 1691 type: "button", 1692 variant: "outline", 1693 disabled: disabled || scanning, 1694 onClick: ()=>inputRef.current?.click(), 1695 children: [ 1696 scanning ? /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__4["jsx"])(__TURBOPACK__imported__module__632781__["Loader2"], { 1697 className: "mr-2 h-4 w-4 animate-spin", 1698 "aria-hidden": true 1699 }) : /*#__PURE__*/ (0, __TURBOPACK__imported__module__843476__4["jsx"])(__TURBOPACK__imported__module__119194__["default"], { 1700 className: "mr-2 h-4 w-4", 1701 "aria-hidden": true 1702 }), 1703 scanning ? t('genikos_expenses.scan.scanning', 'Scanningâ¦') : t('genikos_expenses.scan.action', 'Scan PDF / receipt') 1704 ] 1705 }) 1706 ] 1707 }); 1708} 1709__turbopack_context__.s([ 1710 "ExpenseScanFromFileButton", 1711 0, 1712 ExpenseScanFromFileButton 1713], 447654); 1714}), 1715]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.