"use strict"; (() => { // wwwroot/ts/modules/sidebar.ts var SidebarController = class { constructor() { this.menuToggle = null; this.appLayout = null; this.menuTooltip = null; this.menuToggle = document.getElementById("menuToggle"); this.appLayout = document.querySelector("swp-app-layout"); this.menuTooltip = document.getElementById("menuTooltip"); this.setupListeners(); this.setupTooltips(); this.restoreState(); } /** * Check if sidebar is collapsed */ get isCollapsed() { return this.appLayout?.classList.contains("menu-collapsed") ?? false; } /** * Toggle sidebar collapsed state */ toggle() { if (!this.appLayout) return; this.appLayout.classList.toggle("menu-collapsed"); localStorage.setItem("sidebar-collapsed", String(this.isCollapsed)); } /** * Collapse the sidebar */ collapse() { this.appLayout?.classList.add("menu-collapsed"); localStorage.setItem("sidebar-collapsed", "true"); } /** * Expand the sidebar */ expand() { this.appLayout?.classList.remove("menu-collapsed"); localStorage.setItem("sidebar-collapsed", "false"); } setupListeners() { this.menuToggle?.addEventListener("click", () => this.toggle()); } setupTooltips() { if (!this.menuTooltip) return; const menuItems = document.querySelectorAll("swp-side-menu-item[data-tooltip]"); menuItems.forEach((item) => { item.addEventListener("mouseenter", () => this.showTooltip(item)); item.addEventListener("mouseleave", () => this.hideTooltip()); }); } showTooltip(item) { if (!this.isCollapsed || !this.menuTooltip) return; const rect = item.getBoundingClientRect(); const tooltipText = item.dataset.tooltip; if (!tooltipText) return; this.menuTooltip.textContent = tooltipText; this.menuTooltip.style.left = `${rect.right + 8}px`; this.menuTooltip.style.top = `${rect.top + rect.height / 2}px`; this.menuTooltip.style.transform = "translateY(-50%)"; this.menuTooltip.showPopover(); } hideTooltip() { this.menuTooltip?.hidePopover(); } restoreState() { if (!this.appLayout) return; if (localStorage.getItem("sidebar-collapsed") === "true") { this.appLayout.classList.add("menu-collapsed"); } } }; // wwwroot/ts/modules/drawers.ts var DrawerController = class { constructor() { this.profileDrawer = null; this.notificationDrawer = null; this.todoDrawer = null; this.newTodoDrawer = null; this.overlay = null; this.activeDrawer = null; this.activeGenericDrawer = null; this.profileDrawer = document.getElementById("profileDrawer"); this.notificationDrawer = document.getElementById("notificationDrawer"); this.todoDrawer = document.getElementById("todoDrawer"); this.newTodoDrawer = document.getElementById("newTodoDrawer"); this.overlay = document.getElementById("drawerOverlay"); this.setupListeners(); this.setupGenericDrawers(); } /** * Get currently active drawer name */ get active() { return this.activeDrawer; } /** * Open a drawer by name */ open(name) { this.closeAll(); const drawer = this.getDrawer(name); if (drawer && this.overlay) { drawer.classList.add("active"); this.overlay.classList.add("active"); document.body.style.overflow = "hidden"; this.activeDrawer = name; } } /** * Close a specific drawer */ close(name) { const drawer = this.getDrawer(name); drawer?.classList.remove("active"); if (this.overlay && !document.querySelector('.active[class*="drawer"]')) { this.overlay.classList.remove("active"); document.body.style.overflow = ""; } if (this.activeDrawer === name) { this.activeDrawer = null; } } /** * Close all drawers */ closeAll() { [this.profileDrawer, this.notificationDrawer, this.todoDrawer, this.newTodoDrawer].forEach((drawer) => drawer?.classList.remove("active")); this.closeGenericDrawer(); this.overlay?.classList.remove("active"); document.body.style.overflow = ""; this.activeDrawer = null; } /** * Open a generic drawer by ID */ openGenericDrawer(drawerId) { this.closeAll(); const drawer = document.getElementById(drawerId); if (drawer && this.overlay) { drawer.classList.add("open"); this.overlay.classList.add("active"); document.body.style.overflow = "hidden"; this.activeGenericDrawer = drawer; } } /** * Close the currently open generic drawer */ closeGenericDrawer() { this.activeGenericDrawer?.classList.remove("open"); this.activeGenericDrawer = null; } /** * Open profile drawer */ openProfile() { this.open("profile"); } /** * Open notification drawer */ openNotification() { this.open("notification"); } /** * Open todo drawer (slides on top of profile) */ openTodo() { this.todoDrawer?.classList.add("active"); } /** * Close todo drawer */ closeTodo() { this.todoDrawer?.classList.remove("active"); this.closeNewTodo(); } /** * Open new todo drawer */ openNewTodo() { this.newTodoDrawer?.classList.add("active"); } /** * Close new todo drawer */ closeNewTodo() { this.newTodoDrawer?.classList.remove("active"); } /** * Mark all notifications as read */ markAllNotificationsRead() { if (!this.notificationDrawer) return; const unreadItems = this.notificationDrawer.querySelectorAll( 'swp-notification-item[data-unread="true"]' ); unreadItems.forEach((item) => item.removeAttribute("data-unread")); const badge = document.querySelector("swp-notification-badge"); if (badge) { badge.style.display = "none"; } } getDrawer(name) { switch (name) { case "profile": return this.profileDrawer; case "notification": return this.notificationDrawer; case "todo": return this.todoDrawer; case "newTodo": return this.newTodoDrawer; } } setupListeners() { document.getElementById("profileTrigger")?.addEventListener("click", () => this.openProfile()); document.getElementById("drawerClose")?.addEventListener("click", () => this.close("profile")); document.getElementById("notificationsBtn")?.addEventListener("click", () => this.openNotification()); document.getElementById("notificationDrawerClose")?.addEventListener("click", () => this.close("notification")); document.getElementById("markAllRead")?.addEventListener("click", () => this.markAllNotificationsRead()); document.getElementById("openTodoDrawer")?.addEventListener("click", () => this.openTodo()); document.getElementById("todoDrawerBack")?.addEventListener("click", () => this.closeTodo()); document.getElementById("addTodoBtn")?.addEventListener("click", () => this.openNewTodo()); document.getElementById("newTodoDrawerBack")?.addEventListener("click", () => this.closeNewTodo()); document.getElementById("cancelNewTodo")?.addEventListener("click", () => this.closeNewTodo()); document.getElementById("saveNewTodo")?.addEventListener("click", () => this.closeNewTodo()); this.overlay?.addEventListener("click", () => this.closeAll()); document.addEventListener("keydown", (e) => { if (e.key === "Escape") this.closeAll(); }); this.todoDrawer?.addEventListener("click", (e) => this.handleTodoClick(e)); document.addEventListener("click", (e) => this.handleVisibilityClick(e)); } handleTodoClick(e) { const target = e.target; const todoItem = target.closest("swp-todo-item"); const checkbox = target.closest("swp-todo-checkbox"); if (checkbox && todoItem) { const isCompleted = todoItem.dataset.completed === "true"; if (isCompleted) { todoItem.removeAttribute("data-completed"); } else { todoItem.dataset.completed = "true"; } } const sectionHeader = target.closest("swp-todo-section-header"); if (sectionHeader) { const section = sectionHeader.closest("swp-todo-section"); section?.classList.toggle("collapsed"); } } handleVisibilityClick(e) { const target = e.target; const option = target.closest("swp-visibility-option"); if (option) { document.querySelectorAll("swp-visibility-option").forEach((o) => o.classList.remove("active")); option.classList.add("active"); } } /** * Setup generic drawer triggers and close buttons * Uses data-drawer-trigger="drawer-id" and data-drawer-close attributes */ setupGenericDrawers() { document.addEventListener("click", (e) => { const target = e.target; const trigger = target.closest("[data-drawer-trigger]"); if (trigger) { const drawerId = trigger.dataset.drawerTrigger; if (drawerId) { this.openGenericDrawer(drawerId); } } }); document.addEventListener("click", (e) => { const target = e.target; const closeBtn = target.closest("[data-drawer-close]"); if (closeBtn) { this.closeGenericDrawer(); this.overlay?.classList.remove("active"); document.body.style.overflow = ""; } }); } }; // wwwroot/ts/modules/theme.ts var ThemeController = class _ThemeController { static { this.STORAGE_KEY = "theme-preference"; } static { this.DARK_CLASS = "dark-mode"; } static { this.LIGHT_CLASS = "light-mode"; } constructor() { this.root = document.documentElement; this.themeOptions = document.querySelectorAll("swp-theme-option"); this.applyTheme(this.current); this.updateUI(); this.setupListeners(); } /** * Get the current theme setting */ get current() { const stored = localStorage.getItem(_ThemeController.STORAGE_KEY); if (stored === "dark" || stored === "light" || stored === "system") { return stored; } return "system"; } /** * Check if dark mode is currently active */ get isDark() { return this.root.classList.contains(_ThemeController.DARK_CLASS) || this.systemPrefersDark && !this.root.classList.contains(_ThemeController.LIGHT_CLASS); } /** * Check if system prefers dark mode */ get systemPrefersDark() { return window.matchMedia("(prefers-color-scheme: dark)").matches; } /** * Set theme and persist preference */ set(theme) { localStorage.setItem(_ThemeController.STORAGE_KEY, theme); this.applyTheme(theme); this.updateUI(); } /** * Toggle between light and dark themes */ toggle() { this.set(this.isDark ? "light" : "dark"); } applyTheme(theme) { this.root.classList.remove(_ThemeController.DARK_CLASS, _ThemeController.LIGHT_CLASS); if (theme === "dark") { this.root.classList.add(_ThemeController.DARK_CLASS); } else if (theme === "light") { this.root.classList.add(_ThemeController.LIGHT_CLASS); } } updateUI() { if (!this.themeOptions) return; const darkActive = this.isDark; this.themeOptions.forEach((option) => { const theme = option.dataset.theme; const isActive = theme === "dark" && darkActive || theme === "light" && !darkActive; option.classList.toggle("active", isActive); }); } setupListeners() { this.themeOptions.forEach((option) => { option.addEventListener("click", (e) => this.handleOptionClick(e)); }); window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => this.handleSystemChange()); } handleOptionClick(e) { const target = e.target; const option = target.closest("swp-theme-option"); if (option) { const theme = option.dataset.theme; if (theme) { this.set(theme); } } } handleSystemChange() { if (this.current === "system") { this.updateUI(); } } }; // wwwroot/ts/modules/search.ts var SearchController = class { constructor() { this.input = null; this.container = null; this.input = document.getElementById("globalSearch"); this.container = document.querySelector("swp-topbar-search"); this.setupListeners(); } /** * Get current search value */ get value() { return this.input?.value ?? ""; } /** * Set search value */ set value(val) { if (this.input) { this.input.value = val; } } /** * Focus the search input */ focus() { this.input?.focus(); } /** * Blur the search input */ blur() { this.input?.blur(); } /** * Clear the search input */ clear() { this.value = ""; } setupListeners() { document.addEventListener("keydown", (e) => this.handleKeyboard(e)); if (this.input) { this.input.addEventListener("input", (e) => this.handleInput(e)); const form = this.input.closest("form"); form?.addEventListener("submit", (e) => this.handleSubmit(e)); } } handleKeyboard(e) { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); this.focus(); return; } if (e.key === "Escape" && document.activeElement === this.input) { this.blur(); } } handleInput(e) { const target = e.target; const query = target.value.trim(); document.dispatchEvent(new CustomEvent("app:search", { detail: { query }, bubbles: true })); } handleSubmit(e) { e.preventDefault(); const query = this.value.trim(); if (!query) return; document.dispatchEvent(new CustomEvent("app:search-submit", { detail: { query }, bubbles: true })); } }; // wwwroot/ts/modules/lockscreen.ts var LockScreenController = class _LockScreenController { constructor(drawers) { // Demo PIN this.lockScreen = null; this.pinInput = null; this.pinKeypad = null; this.lockTimeEl = null; this.pinDigits = null; this.currentPin = ""; this.drawers = null; this.drawers = drawers ?? null; this.lockScreen = document.getElementById("lockScreen"); this.pinInput = document.getElementById("pinInput"); this.pinKeypad = document.getElementById("pinKeypad"); this.lockTimeEl = document.getElementById("lockTime"); this.pinDigits = this.pinInput?.querySelectorAll("swp-pin-digit") ?? null; this.setupListeners(); } static { this.CORRECT_PIN = "1234"; } /** * Check if lock screen is active */ get isActive() { return this.lockScreen?.classList.contains("active") ?? false; } /** * Show the lock screen */ show() { this.drawers?.closeAll(); if (this.lockScreen) { this.lockScreen.classList.add("active"); document.body.style.overflow = "hidden"; } this.currentPin = ""; this.updateDisplay(); if (this.lockTimeEl) { this.lockTimeEl.textContent = `L\xE5st kl. ${this.formatTime()}`; } } /** * Hide the lock screen */ hide() { if (this.lockScreen) { this.lockScreen.classList.remove("active"); document.body.style.overflow = ""; } this.currentPin = ""; this.updateDisplay(); } formatTime() { const now = /* @__PURE__ */ new Date(); const hours = now.getHours().toString().padStart(2, "0"); const minutes = now.getMinutes().toString().padStart(2, "0"); return `${hours}:${minutes}`; } updateDisplay() { if (!this.pinDigits) return; this.pinDigits.forEach((digit, index) => { digit.classList.remove("filled", "error"); if (index < this.currentPin.length) { digit.textContent = "\u2022"; digit.classList.add("filled"); } else { digit.textContent = ""; } }); } showError() { if (!this.pinDigits) return; this.pinDigits.forEach((digit) => digit.classList.add("error")); this.pinInput?.classList.add("shake"); setTimeout(() => { this.currentPin = ""; this.updateDisplay(); this.pinInput?.classList.remove("shake"); }, 500); } verify() { if (this.currentPin === _LockScreenController.CORRECT_PIN) { this.hide(); } else { this.showError(); } } addDigit(digit) { if (this.currentPin.length >= 4) return; this.currentPin += digit; this.updateDisplay(); if (this.currentPin.length === 4) { setTimeout(() => this.verify(), 200); } } removeDigit() { if (this.currentPin.length === 0) return; this.currentPin = this.currentPin.slice(0, -1); this.updateDisplay(); } clearPin() { this.currentPin = ""; this.updateDisplay(); } setupListeners() { this.pinKeypad?.addEventListener("click", (e) => this.handleKeypadClick(e)); document.addEventListener("keydown", (e) => this.handleKeyboard(e)); document.querySelector("swp-side-menu-action.lock")?.addEventListener("click", () => this.show()); } handleKeypadClick(e) { const target = e.target; const key = target.closest("swp-pin-key"); if (!key) return; const digit = key.dataset.digit; const action = key.dataset.action; if (digit) { this.addDigit(digit); } else if (action === "backspace") { this.removeDigit(); } else if (action === "clear") { this.clearPin(); } } handleKeyboard(e) { if (!this.isActive) return; e.preventDefault(); if (e.key >= "0" && e.key <= "9") { this.addDigit(e.key); } else if (e.key === "Backspace") { this.removeDigit(); } else if (e.key === "Escape") { this.clearPin(); } } }; // wwwroot/ts/modules/cash.ts var CashController = class { constructor() { // Base values (from system - would come from server in real app) this.startBalance = 2e3; this.cashSales = 3540; this.setupTabs(); this.setupCashCalculation(); this.setupCheckboxSelection(); this.setupApprovalCheckbox(); this.setupDateFilters(); this.setupRowToggle(); this.setupDraftRowClick(); } /** * Setup tab switching functionality */ setupTabs() { const tabs = document.querySelectorAll("swp-tab[data-tab]"); tabs.forEach((tab) => { tab.addEventListener("click", () => { const targetTab = tab.dataset.tab; if (targetTab) { this.switchToTab(targetTab); } }); }); } /** * Switch to a specific tab by name */ switchToTab(targetTab) { const tabs = document.querySelectorAll("swp-tab[data-tab]"); const contents = document.querySelectorAll("swp-tab-content[data-tab]"); const statsBars = document.querySelectorAll("swp-cash-stats[data-for-tab]"); tabs.forEach((t) => { if (t.dataset.tab === targetTab) { t.classList.add("active"); } else { t.classList.remove("active"); } }); contents.forEach((content) => { if (content.dataset.tab === targetTab) { content.classList.add("active"); } else { content.classList.remove("active"); } }); statsBars.forEach((stats) => { if (stats.dataset.forTab === targetTab) { stats.classList.add("active"); } else { stats.classList.remove("active"); } }); } /** * Setup cash calculation with real-time updates */ setupCashCalculation() { const payoutsInput = document.getElementById("payouts"); const toBankInput = document.getElementById("toBank"); const actualCashInput = document.getElementById("actualCash"); if (!payoutsInput || !toBankInput || !actualCashInput) return; const calculate = () => this.calculateCash(payoutsInput, toBankInput, actualCashInput); payoutsInput.addEventListener("input", calculate); toBankInput.addEventListener("input", calculate); actualCashInput.addEventListener("input", calculate); calculate(); } /** * Calculate expected cash and difference */ calculateCash(payoutsInput, toBankInput, actualCashInput) { const payouts = this.parseNumber(payoutsInput.value); const toBank = this.parseNumber(toBankInput.value); const actual = this.parseNumber(actualCashInput.value); const expectedCash = this.startBalance + this.cashSales - payouts - toBank; const expectedElement = document.getElementById("expectedCash"); if (expectedElement) { expectedElement.textContent = this.formatNumber(expectedCash); } this.updateDifference(actual, expectedCash, actualCashInput.value); } /** * Update difference box with color coding */ updateDifference(actual, expected, rawValue) { const box = document.getElementById("differenceBox"); const value = document.getElementById("differenceValue"); if (!box || !value) return; const diff = actual - expected; box.classList.remove("positive", "negative", "neutral"); if (actual === 0 && rawValue === "") { value.textContent = "\u2013 kr"; box.classList.add("neutral"); } else if (diff > 0) { value.textContent = "+" + this.formatNumber(diff) + " kr"; box.classList.add("positive"); } else if (diff < 0) { value.textContent = this.formatNumber(diff) + " kr"; box.classList.add("negative"); } else { value.textContent = "0,00 kr"; box.classList.add("neutral"); } } /** * Setup checkbox selection for table rows */ setupCheckboxSelection() { const selectAll = document.getElementById("selectAll"); const rowCheckboxes = document.querySelectorAll(".row-select"); const exportBtn = document.getElementById("exportBtn"); const selectionCount = document.getElementById("selectionCount"); if (!selectAll || !exportBtn || !selectionCount) return; const updateSelection = () => { const checked = document.querySelectorAll(".row-select:checked"); const count = checked.length; selectionCount.textContent = count === 0 ? "0 valgt" : `${count} valgt`; exportBtn.disabled = count === 0; selectAll.checked = count === rowCheckboxes.length && count > 0; selectAll.indeterminate = count > 0 && count < rowCheckboxes.length; }; selectAll.addEventListener("change", () => { rowCheckboxes.forEach((cb) => cb.checked = selectAll.checked); updateSelection(); }); rowCheckboxes.forEach((cb) => { cb.addEventListener("change", updateSelection); cb.addEventListener("click", (e) => e.stopPropagation()); }); } /** * Setup approval checkbox to enable/disable approve button */ setupApprovalCheckbox() { const checkbox = document.getElementById("confirmCheckbox"); const approveBtn = document.getElementById("approveBtn"); if (!checkbox || !approveBtn) return; checkbox.addEventListener("change", () => { approveBtn.disabled = !checkbox.checked; }); } /** * Setup date filter defaults (last 30 days) */ setupDateFilters() { const dateFrom = document.getElementById("dateFrom"); const dateTo = document.getElementById("dateTo"); if (!dateFrom || !dateTo) return; const today = /* @__PURE__ */ new Date(); const thirtyDaysAgo = new Date(today); thirtyDaysAgo.setDate(today.getDate() - 30); dateTo.value = this.formatDateISO(today); dateFrom.value = this.formatDateISO(thirtyDaysAgo); } /** * Format number as Danish currency */ formatNumber(num) { return num.toLocaleString("da-DK", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } /** * Parse Danish number format */ parseNumber(str) { if (!str) return 0; return parseFloat(str.replace(/\./g, "").replace(",", ".")) || 0; } /** * Format date as ISO string (YYYY-MM-DD) */ formatDateISO(date) { return date.toISOString().split("T")[0]; } /** * Setup row toggle for expandable details */ setupRowToggle() { const rows = document.querySelectorAll("swp-cash-table-row[data-id]:not(.draft-row)"); rows.forEach((row) => { const rowId = row.getAttribute("data-id"); if (!rowId) return; const detail = document.querySelector(`swp-cash-row-detail[data-for="${rowId}"]`); if (!detail) return; row.addEventListener("click", (e) => { if (e.target.closest('input[type="checkbox"]')) return; const icon = row.querySelector("swp-row-toggle i"); const isExpanded = row.classList.contains("expanded"); document.querySelectorAll("swp-cash-table-row.expanded").forEach((r) => { if (r !== row) { const otherId = r.getAttribute("data-id"); if (otherId) { const otherDetail = document.querySelector(`swp-cash-row-detail[data-for="${otherId}"]`); const otherIcon = r.querySelector("swp-row-toggle i"); if (otherDetail && otherIcon) { this.collapseRow(r, otherDetail, otherIcon); } } } }); if (isExpanded) { this.collapseRow(row, detail, icon); } else { this.expandRow(row, detail, icon); } }); }); } /** * Expand a row with animation */ expandRow(row, detail, icon) { row.classList.add("expanded"); detail.classList.add("expanded"); icon?.animate([ { transform: "rotate(0deg)" }, { transform: "rotate(90deg)" } ], { duration: 200, easing: "ease-out", fill: "forwards" }); const content = detail.querySelector("swp-row-detail-content"); if (content) { const height = content.offsetHeight; detail.animate([ { height: "0px", opacity: 0 }, { height: `${height}px`, opacity: 1 } ], { duration: 250, easing: "ease-out", fill: "forwards" }); } } /** * Collapse a row with animation */ collapseRow(row, detail, icon) { icon?.animate([ { transform: "rotate(90deg)" }, { transform: "rotate(0deg)" } ], { duration: 200, easing: "ease-out", fill: "forwards" }); const content = detail.querySelector("swp-row-detail-content"); if (content) { const height = content.offsetHeight; const animation = detail.animate([ { height: `${height}px`, opacity: 1 }, { height: "0px", opacity: 0 } ], { duration: 200, easing: "ease-out", fill: "forwards" }); animation.onfinish = () => { row.classList.remove("expanded"); detail.classList.remove("expanded"); }; } else { row.classList.remove("expanded"); detail.classList.remove("expanded"); } } /** * Setup draft row click to navigate to reconciliation tab */ setupDraftRowClick() { const draftRow = document.querySelector("swp-cash-table-row.draft-row"); if (!draftRow) return; draftRow.style.cursor = "pointer"; draftRow.addEventListener("click", (e) => { if (e.target.closest('input[type="checkbox"]')) return; this.switchToTab("afstemning"); }); } }; // wwwroot/ts/modules/employees.ts var EmployeesController = class { constructor() { this.ratesSync = null; this.listView = null; this.detailView = null; this.listView = document.getElementById("employees-list-view"); this.detailView = document.getElementById("employee-detail-view"); if (!this.listView) return; this.setupListTabs(); this.setupDetailTabs(); this.setupChevronNavigation(); this.setupBackNavigation(); this.setupHistoryNavigation(); this.restoreStateFromUrl(); this.ratesSync = new RatesSyncController(); } /** * Setup popstate listener for browser back/forward */ setupHistoryNavigation() { window.addEventListener("popstate", (e) => { if (e.state?.employeeKey) { this.showDetailViewInternal(e.state.employeeKey); } else { this.showListViewInternal(); } }); } /** * Restore view state from URL on page load */ restoreStateFromUrl() { const hash = window.location.hash; if (hash.startsWith("#employee-")) { const employeeKey = hash.substring(1); this.showDetailViewInternal(employeeKey); } } /** * Setup tab switching for the list view */ setupListTabs() { if (!this.listView) return; const tabs = this.listView.querySelectorAll("swp-tab-bar > swp-tab[data-tab]"); tabs.forEach((tab) => { tab.addEventListener("click", () => { const targetTab = tab.dataset.tab; if (targetTab) { this.switchTab(this.listView, targetTab); } }); }); } /** * Setup tab switching for the detail view */ setupDetailTabs() { if (!this.detailView) return; const tabs = this.detailView.querySelectorAll("swp-tab-bar > swp-tab[data-tab]"); tabs.forEach((tab) => { tab.addEventListener("click", () => { const targetTab = tab.dataset.tab; if (targetTab) { this.switchTab(this.detailView, targetTab); } }); }); } /** * Switch to a specific tab within a container */ switchTab(container, targetTab) { const tabs = container.querySelectorAll("swp-tab-bar > swp-tab[data-tab]"); const contents = container.querySelectorAll("swp-tab-content[data-tab]"); tabs.forEach((t) => { t.classList.toggle("active", t.dataset.tab === targetTab); }); contents.forEach((content) => { content.classList.toggle("active", content.dataset.tab === targetTab); }); } /** * Setup row click to show detail view * Ignores clicks on action buttons */ setupChevronNavigation() { document.addEventListener("click", (e) => { const target = e.target; if (target.closest("swp-icon-btn") || target.closest("swp-table-actions")) { return; } const row = target.closest("swp-employee-row[data-employee-detail]"); if (row) { const employeeKey = row.dataset.employeeDetail; if (employeeKey) { this.showDetailView(employeeKey); } } }); } /** * Setup back button to return to list view */ setupBackNavigation() { document.addEventListener("click", (e) => { const target = e.target; const backLink = target.closest("[data-employee-back]"); if (backLink) { this.showListView(); } }); } /** * Show the detail view and hide list view (with history push) */ showDetailView(employeeKey) { history.pushState( { employeeKey }, "", `#${employeeKey}` ); this.showDetailViewInternal(employeeKey); } /** * Show detail view without modifying history (for popstate) */ showDetailViewInternal(employeeKey) { if (this.listView && this.detailView) { this.listView.style.display = "none"; this.detailView.style.display = "block"; this.detailView.dataset.employee = employeeKey; this.switchTab(this.detailView, "general"); } } /** * Show the list view and hide detail view (with history push) */ showListView() { history.pushState( {}, "", window.location.pathname ); this.showListViewInternal(); } /** * Show list view without modifying history (for popstate) */ showListViewInternal() { if (this.listView && this.detailView) { this.detailView.style.display = "none"; this.listView.style.display = "block"; } } }; var RatesSyncController = class { constructor() { this.drawer = null; this.drawer = document.getElementById("rates-drawer"); if (!this.drawer) return; this.setupCheckboxListeners(); this.setupInputListeners(); } /** * Extract rate key from checkbox ID (e.g., "rate-normal-enabled" → "normal") */ extractRateKey(checkboxId) { const match = checkboxId.match(/^rate-(.+)-enabled$/); return match ? match[1] : null; } /** * Setup checkbox change listeners in drawer */ setupCheckboxListeners() { if (!this.drawer) return; this.drawer.addEventListener("change", (e) => { const target = e.target; if (target.type !== "checkbox" || !target.id) return; const rateKey = this.extractRateKey(target.id); if (!rateKey) return; const isChecked = target.checked; const row = target.closest("swp-data-row"); if (!row) return; const label = row.querySelector("swp-data-label"); const input = row.querySelector("swp-data-input"); if (label) label.classList.toggle("disabled", !isChecked); if (input) input.classList.toggle("disabled", !isChecked); this.toggleCardRow(rateKey, isChecked); if (isChecked) { const textInput = document.getElementById(`rate-${rateKey}`); if (textInput) { this.syncValueToCard(rateKey, textInput.value); } } }); } /** * Setup input change listeners in drawer */ setupInputListeners() { if (!this.drawer) return; this.drawer.addEventListener("input", (e) => { const target = e.target; if (target.type !== "text" || !target.id) return; const match = target.id.match(/^rate-(.+)$/); if (!match) return; const rateKey = match[1]; if (rateKey.endsWith("-enabled")) return; this.syncValueToCard(rateKey, target.value); }); } /** * Toggle card row visibility by ID */ toggleCardRow(rateKey, visible) { const cardRow = document.getElementById(`card-${rateKey}`); if (cardRow) { cardRow.style.display = visible ? "" : "none"; } } /** * Format number with 2 decimals using Danish locale (comma as decimal separator) */ formatNumber(value) { const normalized = value.replace(",", "."); const num = parseFloat(normalized); if (isNaN(num)) return value; return num.toFixed(2).replace(".", ","); } /** * Sync value from drawer to card by ID */ syncValueToCard(rateKey, value) { const cardInput = document.getElementById(`value-${rateKey}`); if (!cardInput) return; const textInput = document.getElementById(`rate-${rateKey}`); const inputContainer = textInput?.closest("swp-data-input"); const unit = inputContainer?.textContent?.trim().replace(value, "").trim() || "kr"; const formattedValue = this.formatNumber(value); cardInput.value = `${formattedValue} ${unit}`; } }; // wwwroot/ts/app.ts var App = class { constructor() { this.sidebar = new SidebarController(); this.drawers = new DrawerController(); this.theme = new ThemeController(); this.search = new SearchController(); this.lockScreen = new LockScreenController(this.drawers); this.cash = new CashController(); this.employees = new EmployeesController(); } }; var app; function init() { app = new App(); if (typeof window !== "undefined") { window.app = app; } } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } var app_default = App; })(); //# sourceMappingURL=app.js.map