PlanTempusApp/PlanTempus.Application/wwwroot/js/app.js

928 lines
97 KiB
JavaScript
Raw Normal View History

var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// wwwroot/ts/modules/sidebar.ts
var _SidebarController = class _SidebarController {
2026-01-10 20:39:17 +01:00
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() {
2026-01-11 18:18:36 +01:00
if (!this.appLayout) return;
2026-01-10 20:39:17 +01:00
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() {
2026-01-11 18:18:36 +01:00
if (!this.menuTooltip) return;
2026-01-10 20:39:17 +01:00
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) {
2026-01-11 18:18:36 +01:00
if (!this.isCollapsed || !this.menuTooltip) return;
2026-01-10 20:39:17 +01:00
const rect = item.getBoundingClientRect();
const tooltipText = item.dataset.tooltip;
2026-01-11 18:18:36 +01:00
if (!tooltipText) return;
2026-01-10 20:39:17 +01:00
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() {
2026-01-11 18:18:36 +01:00
if (!this.appLayout) return;
2026-01-10 20:39:17 +01:00
if (localStorage.getItem("sidebar-collapsed") === "true") {
this.appLayout.classList.add("menu-collapsed");
}
}
};
__name(_SidebarController, "SidebarController");
var SidebarController = _SidebarController;
2026-01-10 20:39:17 +01:00
// wwwroot/ts/modules/drawers.ts
var _DrawerController = class _DrawerController {
2026-01-10 20:39:17 +01:00
constructor() {
this.profileDrawer = null;
this.notificationDrawer = null;
this.todoDrawer = null;
this.newTodoDrawer = null;
this.overlay = null;
this.activeDrawer = null;
2026-01-11 18:18:36 +01:00
this.activeGenericDrawer = null;
2026-01-10 20:39:17 +01:00
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();
2026-01-11 18:18:36 +01:00
this.setupGenericDrawers();
2026-01-10 20:39:17 +01:00
}
/**
* 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"));
2026-01-11 18:18:36 +01:00
this.closeGenericDrawer();
2026-01-10 20:39:17 +01:00
this.overlay?.classList.remove("active");
document.body.style.overflow = "";
this.activeDrawer = null;
}
2026-01-11 18:18:36 +01:00
/**
* 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;
}
2026-01-10 20:39:17 +01:00
/**
* 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() {
2026-01-11 18:18:36 +01:00
if (!this.notificationDrawer) return;
2026-01-10 20:39:17 +01:00
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) => {
2026-01-11 18:18:36 +01:00
if (e.key === "Escape") this.closeAll();
2026-01-10 20:39:17 +01:00
});
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");
}
}
2026-01-11 18:18:36 +01:00
/**
* 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 = "";
}
});
}
2026-01-10 20:39:17 +01:00
};
__name(_DrawerController, "DrawerController");
var DrawerController = _DrawerController;
2026-01-10 20:39:17 +01:00
// wwwroot/ts/modules/theme.ts
var _ThemeController = class _ThemeController {
2026-01-10 20:39:17 +01:00
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() {
2026-01-11 18:18:36 +01:00
if (!this.themeOptions) return;
2026-01-10 20:39:17 +01:00
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();
}
}
};
__name(_ThemeController, "ThemeController");
_ThemeController.STORAGE_KEY = "theme-preference";
_ThemeController.DARK_CLASS = "dark-mode";
_ThemeController.LIGHT_CLASS = "light-mode";
var ThemeController = _ThemeController;
2026-01-10 20:39:17 +01:00
// wwwroot/ts/modules/search.ts
var _SearchController = class _SearchController {
2026-01-10 20:39:17 +01:00
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();
2026-01-11 18:18:36 +01:00
if (!query) return;
2026-01-10 20:39:17 +01:00
document.dispatchEvent(new CustomEvent("app:search-submit", {
detail: { query },
bubbles: true
}));
}
};
__name(_SearchController, "SearchController");
var SearchController = _SearchController;
2026-01-10 20:39:17 +01:00
// wwwroot/ts/modules/lockscreen.ts
var _LockScreenController = class _LockScreenController {
2026-01-10 20:39:17 +01:00
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();
}
/**
* 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() {
2026-01-11 18:18:36 +01:00
if (!this.pinDigits) return;
2026-01-10 20:39:17 +01:00
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() {
2026-01-11 18:18:36 +01:00
if (!this.pinDigits) return;
2026-01-10 20:39:17 +01:00
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) {
2026-01-11 18:18:36 +01:00
if (this.currentPin.length >= 4) return;
2026-01-10 20:39:17 +01:00
this.currentPin += digit;
this.updateDisplay();
if (this.currentPin.length === 4) {
setTimeout(() => this.verify(), 200);
}
}
removeDigit() {
2026-01-11 18:18:36 +01:00
if (this.currentPin.length === 0) return;
2026-01-10 20:39:17 +01:00
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");
2026-01-11 18:18:36 +01:00
if (!key) return;
2026-01-10 20:39:17 +01:00
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) {
2026-01-11 18:18:36 +01:00
if (!this.isActive) return;
2026-01-10 20:39:17 +01:00
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();
}
}
};
__name(_LockScreenController, "LockScreenController");
_LockScreenController.CORRECT_PIN = "1234";
var LockScreenController = _LockScreenController;
2026-01-11 21:42:24 +01:00
// wwwroot/ts/modules/cash.ts
var _CashController = class _CashController {
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]");
2026-01-11 21:42:24 +01:00
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 = /* @__PURE__ */ __name(() => this.calculateCash(payoutsInput, toBankInput, actualCashInput), "calculate");
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 = /* @__PURE__ */ __name(() => {
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;
}, "updateSelection");
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() {
2026-01-11 21:42:24 +01:00
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;
2026-01-11 21:42:24 +01:00
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");
2026-01-11 21:42:24 +01:00
document.querySelectorAll("swp-cash-table-row.expanded").forEach((r) => {
if (r !== row) {
const otherId = r.getAttribute("data-id");
if (otherId) {
2026-01-11 21:42:24 +01:00
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");
}
}
/**
2026-01-11 21:42:24 +01:00
* Setup draft row click to navigate to reconciliation tab
*/
setupDraftRowClick() {
2026-01-11 21:42:24 +01:00
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");
});
}
};
2026-01-11 21:42:24 +01:00
__name(_CashController, "CashController");
var CashController = _CashController;
2026-01-10 20:39:17 +01:00
// wwwroot/ts/app.ts
var _App = class _App {
2026-01-10 20:39:17 +01:00
constructor() {
this.sidebar = new SidebarController();
this.drawers = new DrawerController();
this.theme = new ThemeController();
this.search = new SearchController();
this.lockScreen = new LockScreenController(this.drawers);
2026-01-11 21:42:24 +01:00
this.cash = new CashController();
2026-01-10 20:39:17 +01:00
}
};
__name(_App, "App");
var App = _App;
2026-01-10 20:39:17 +01:00
var app;
function init() {
app = new App();
if (typeof window !== "undefined") {
window.app = app;
}
}
__name(init, "init");
2026-01-10 20:39:17 +01:00
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
var app_default = App;
export {
App,
app,
app_default as default
};
2026-01-11 21:42:24 +01:00
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vdHMvbW9kdWxlcy9zaWRlYmFyLnRzIiwgIi4uL3RzL21vZHVsZXMvZHJhd2Vycy50cyIsICIuLi90cy9tb2R1bGVzL3RoZW1lLnRzIiwgIi4uL3RzL21vZHVsZXMvc2VhcmNoLnRzIiwgIi4uL3RzL21vZHVsZXMvbG9ja3NjcmVlbi50cyIsICIuLi90cy9tb2R1bGVzL2Nhc2gudHMiLCAiLi4vdHMvYXBwLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIFNpZGViYXIgQ29udHJvbGxlclxuICpcbiAqIEhhbmRsZXMgc2lkZWJhciBjb2xsYXBzZS9leHBhbmQgYW5kIHRvb2x0aXAgZnVuY3Rpb25hbGl0eVxuICovXG5cbmV4cG9ydCBjbGFzcyBTaWRlYmFyQ29udHJvbGxlciB7XG4gIHByaXZhdGUgbWVudVRvZ2dsZTogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBhcHBMYXlvdXQ6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgbWVudVRvb2x0aXA6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5tZW51VG9nZ2xlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21lbnVUb2dnbGUnKTtcbiAgICB0aGlzLmFwcExheW91dCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ3N3cC1hcHAtbGF5b3V0Jyk7XG4gICAgdGhpcy5tZW51VG9vbHRpcCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtZW51VG9vbHRpcCcpO1xuXG4gICAgdGhpcy5zZXR1cExpc3RlbmVycygpO1xuICAgIHRoaXMuc2V0dXBUb29sdGlwcygpO1xuICAgIHRoaXMucmVzdG9yZVN0YXRlKCk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgc2lkZWJhciBpcyBjb2xsYXBzZWRcbiAgICovXG4gIGdldCBpc0NvbGxhcHNlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5hcHBMYXlvdXQ/LmNsYXNzTGlzdC5jb250YWlucygnbWVudS1jb2xsYXBzZWQnKSA/PyBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUb2dnbGUgc2lkZWJhciBjb2xsYXBzZWQgc3RhdGVcbiAgICovXG4gIHRvZ2dsZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuYXBwTGF5b3V0KSByZXR1cm47XG5cbiAgICB0aGlzLmFwcExheW91dC5jbGFzc0xpc3QudG9nZ2xlKCdtZW51LWNvbGxhcHNlZCcpO1xuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCdzaWRlYmFyLWNvbGxhcHNlZCcsIFN0cmluZyh0aGlzLmlzQ29sbGFwc2VkKSk7XG4gIH1cblxuICAvKipcbiAgICogQ29sbGFwc2UgdGhlIHNpZGViYXJcbiAgICovXG4gIGNvbGxhcHNlKCk6IHZvaWQge1xuICAgIHRoaXMuYXBwTGF5b3V0Py5jbGFzc0xpc3QuYWRkKCdtZW51LWNvbGxhcHNlZCcpO1xuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCdzaWRlYmFyLWNvbGxhcHNlZCcsICd0cnVlJyk7XG4gIH1cblxuICAvKipcbiAgICogRXhwYW5kIHRoZSBzaWRlYmFyXG4gICAqL1xuICBleHBhbmQoKTogdm9pZCB7XG4gICAgdGhpcy5hcHBMYXlvdXQ/LmNsYXNzTGlzdC5yZW1vdmUoJ21lbnUtY29sbGFwc2VkJyk7XG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3NpZGViYXItY29sbGFwc2VkJywgJ2ZhbHNlJyk7XG4gIH1cblxuICBwcml2YXRlIHNldHVwTGlzdGVuZXJzKCk6IHZvaWQge1xuICAgIHRoaXMubWVudVRvZ2dsZT8uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB0aGlzLnRvZ2dsZSgpKTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBUb29sdGlwcygpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMubWVudVRvb2x0aXApIHJldHVybjtcblxuICAgIGNvbnN0IG1lbnVJdGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGw8SFRNTEVsZW1lbnQ+KCdzd3Atc2lkZS1tZW51LWl0ZW1bZGF0YS10b29sdGlwXScpO1xuXG4gICAgbWVudUl0ZW1zLmZvckVhY2goaXRlbSA9PiB7XG4gICAgICBpdGVtLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZW50ZXInLCAoKSA9PiB0aGlzLnNob3dUb29sdGlwKGl0ZW0pKTtcbiAgICAgIGl0ZW0uYWRkRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsICgpID0+IHRoaXMuaGlkZVRvb2x0aXAoKSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHNob3dUb29sdGlwKGl0ZW06IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzQ29sbGFwc2VkIHx8ICF0aGlzLm1lbnVUb29sdGlwKSByZXR1cm47XG5cbiAgICBjb25zdCByZWN0ID0gaXRlbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCB0b29sdGlwVGV4dCA9IGl0ZW0uZGF0YXNldC50b29sdGlwO1xuXG4gICAgaWYgKCF0b29sdGlwVGV4dCkgcmV0dXJuO1xuXG4gICAgdGhpcy5tZW51VG9vbHRpcC50ZXh0Q29udGVudCA9IHRvb2x0aXBUZXh0O1xuICAgIHRoaXMubWVudVRvb2x0aXAuc3R5bGUubGVmdCA9IGAke3JlY3QucmlnaHQgKyA4fXB4YDtcbiAgICB0aGlzLm1lbnVUb29sdGlwLnN0eWxlLnRvcCA9IGAke3JlY3QudG9wICsgcmVjdC5oZWlnaHQgLyAyfXB4YDtcbiAgICB0aGlzLm1lbnVUb29sdGlwLnN0eWxlLnRyYW5zZm9ybSA9ICd0cmFuc2xhdGVZKC01MCUpJztcbiAgICB0aGlzLm1lbnVUb29sdGlwLnNob3dQb3BvdmVyKCk7XG4gIH1cblxuICBwcml2YXRlIGhpZGVUb29sdGlwKCk6IHZvaWQge1xuICAgIHRoaXMubWVudVRvb2x0aXA/LmhpZGVQb3BvdmVyKCk7XG4gIH1cblxuICBwcml2YXRlIHJlc3RvcmVTdGF0ZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuYXBwTGF5b3V0KSByZXR1cm47XG5cbiAgICBpZiAobG9jYWxTdG9yYWdlLmdldEl0ZW0oJ3NpZGViYXItY29sbGFwc2VkJykgPT09ICd0cnVlJykge1xuICAgICAgdGhpcy5hcHBMYXlvdXQuY2xhc3NMaXN0LmFkZCgnbWVudS1jb2xsYXBzZWQnKTtcbiAgICB9XG4gIH1cbn1cbiIsICIvKipcbiAqIERyYXdlciBDb250cm9sbGVyXG4gKlxuICogSGFuZGxlcyBhbGwgZHJhd2VyIGZ1bmN0aW9uYWxpdHkgaW5jbHVkaW5nIHByb2ZpbGUsIG5vdGlmaWNhdGlvbnMsIGFuZCB0b2RvIGRyYXdlcnNcbiAqL1xuXG5leHBvcnQgdHlwZSBEcmF3ZXJOYW1lID0gJ3Byb2Zpb