From a45c7d172987dc81aca961d748d462f3c2d8268f Mon Sep 17 00:00:00 2001 From: Sascha Kappmeier Date: Wed, 28 Oct 2026 13:49:12 +0100 Subject: [PATCH 1/5] feat(reports): let dashboard charts and reports count budget months (#457) A new setting next to the Budget Cycle Start Day chooses whether the dashboard charts and the month-by-month reports (income vs. expenses trend, cash flow, category by month, and their exports) count calendar months, the default, or the user's budget months. With budget months a salary on the 26th counts towards the next month, as on the Budget page. The queries group by date and fold the rows into budget months in PHP, since a budget month can't be cut out of a date in SQL all supported databases run. Year-over-year and the digest keep calendar months. The hero tiles' "vs last month" now compares the current budget period with the whole previous one. It used the summary's calendar-month buckets, which with a start day cut the current period in two. Co-Authored-By: Claude Opus 5.5 --- budget/css/style.css | 6 + budget/lib/Controller/SettingController.php | 2 + budget/lib/Db/ReportScope.php | 31 ++++ budget/lib/Db/TransactionReportQueries.php | 56 +++++-- budget/lib/Service/BudgetCarryoverService.php | 14 ++ budget/lib/Service/BudgetPeriod.php | 25 ++++ .../lib/Service/Report/ReportAggregator.php | 89 +++++++---- budget/lib/Service/ReportService.php | 22 ++- .../src/modules/dashboard/DashboardModule.js | 108 ++++++++------ budget/src/modules/reports/ReportsModule.js | 3 + budget/src/utils/formatters.js | 30 ++++ budget/templates/index.php | 15 ++ .../Unit/Db/TransactionReportQueriesTest.php | 68 +++++++++ .../Service/BudgetCarryoverServiceTest.php | 33 ++++ .../tests/Unit/Service/BudgetPeriodTest.php | 20 +++ .../Service/Report/ReportAggregatorTest.php | 51 +++++++ .../tests/Unit/Service/ReportServiceTest.php | 33 ++++ budget/tests/js/reportMonthGrouping.test.js | 141 ++++++++++++++++++ 18 files changed, 653 insertions(+), 94 deletions(-) create mode 100644 budget/tests/js/reportMonthGrouping.test.js diff --git a/budget/css/style.css b/budget/css/style.css index 8fa820c62..17d9f87b8 100644 --- a/budget/css/style.css +++ b/budget/css/style.css @@ -6879,6 +6879,12 @@ button.danger:hover { .category-chart-header h5 { margin: 0; } +/* Says a chart's or report's months are budget months (#457) */ +.month-grouping-note { + margin: 4px 0 0; + font-size: 12px; + color: var(--color-text-maxcontrast); +} /* Says the bars are budget months when a budget start day is set (#447) */ .category-chart-note { margin: -8px 0 12px; diff --git a/budget/lib/Controller/SettingController.php b/budget/lib/Controller/SettingController.php index 3ea2d13f3..0cd50b6d1 100644 --- a/budget/lib/Controller/SettingController.php +++ b/budget/lib/Controller/SettingController.php @@ -10,6 +10,7 @@ use OCA\Budget\Enum\Currency; use OCA\Budget\Service\AmountColours; use OCA\Budget\Service\AttachmentService; +use OCA\Budget\Service\BudgetCarryoverService; use OCA\Budget\Service\GranularShareService; use OCA\Budget\Service\ImportFolderService; use OCA\Budget\Traits\ApiErrorHandlerTrait; @@ -56,6 +57,7 @@ class SettingController extends Controller { 'export_default_format' => 'csv', 'budget_period' => 'monthly', 'budget_start_day' => '1', + BudgetCarryoverService::REPORT_MONTHS_SETTING => 'calendar', // or 'budget' (#457) 'budget_alert_threshold' => '80', 'budget_alert_scope' => 'all', // or 'manual': only budgets the user set (#389) 'budget_alert_muted_categories' => '[]', diff --git a/budget/lib/Db/ReportScope.php b/budget/lib/Db/ReportScope.php index 4d44adeff..39cef023b 100644 --- a/budget/lib/Db/ReportScope.php +++ b/budget/lib/Db/ReportScope.php @@ -4,6 +4,7 @@ namespace OCA\Budget\Db; +use OCA\Budget\Service\BudgetPeriod; use OCA\Budget\Service\MoneyCalculator; use OCP\DB\QueryBuilder\ICompositeExpression; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -43,6 +44,36 @@ public static function monthExpr(string $alias = 't'): string { return "SUBSTR(CAST({$alias}.date AS CHAR(10)), 1, 7)"; } + /** + * The bucket a month-by-month report groups by. Calendar months + * ($monthStartDay 1) are cut in SQL. A budget month can't be cut out of + * a date in SQL every database runs, so with a budget start day the + * query groups by date and toBudgetMonths() names each date's month. + */ + public static function monthBucketExpr(int $monthStartDay, string $alias = 't'): string { + return $monthStartDay > 1 ? "CAST({$alias}.date AS CHAR(10))" : self::monthExpr($alias); + } + + /** + * Rows grouped by monthBucketExpr(), with $column turned from a date into + * its budget month (Y-m). Several dates then share a month, so the rows + * go through mergeReportHalves() afterwards to add them up. Calendar + * month rows come back unchanged. + * + * @param array[] $rows + * @return array[] + */ + public static function toBudgetMonths(array $rows, int $monthStartDay, string $column = 'month'): array { + if ($monthStartDay <= 1) { + return $rows; + } + foreach ($rows as &$row) { + $row[$column] = BudgetPeriod::monthContaining(substr((string)$row[$column], 0, 10), $monthStartDay); + } + unset($row); + return $rows; + } + /** * Apply user scope to a query — either by userId or by visible account IDs. * Used for granular sharing where the user can see specific shared accounts. diff --git a/budget/lib/Db/TransactionReportQueries.php b/budget/lib/Db/TransactionReportQueries.php index 0738ed0a1..adbdb7b9e 100644 --- a/budget/lib/Db/TransactionReportQueries.php +++ b/budget/lib/Db/TransactionReportQueries.php @@ -217,6 +217,9 @@ function (IQueryBuilder $qb, string $alloc): void { * * @param int[] $tagIds Optional tag filter (OR logic) * @param bool $includeUntagged Include untagged transactions when filtering by tags + * @param int $monthStartDay 1 for calendar months; otherwise the budget + * start day, and 'month' is the budget month + * (BudgetPeriod) each transaction falls in * @return array */ public function getCashFlowByMonth( @@ -228,19 +231,27 @@ public function getCashFlowByMonth( bool $includeUntagged = true, bool $excludeTransfers = false, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { + $bucket = ReportScope::monthBucketExpr($monthStartDay); [$direct, $split] = $this->reportHalves( $userId, $accountId, $startDate, $endDate, $visibleAccountIds, $excludeTransfers, - function (IQueryBuilder $qb, string $alloc) use ($tagIds, $includeUntagged): void { - $qb->select($qb->createFunction(ReportScope::monthExpr() . ' as month')); + function (IQueryBuilder $qb, string $alloc) use ($tagIds, $includeUntagged, $bucket): void { + $qb->select($qb->createFunction($bucket . ' as month')); ReportScope::selectIncomeExpenses($qb, $alloc); $qb->selectAlias($qb->createFunction('COUNT(DISTINCT t.id)'), 'count'); ReportScope::applyTagFilter($qb, $tagIds, $includeUntagged); - $qb->groupBy($qb->createFunction(ReportScope::monthExpr())); + $qb->groupBy($qb->createFunction($bucket)); } ); - $rows = ReportScope::mergeReportHalves($direct, $split, ['month'], ['income', 'expenses'], ['count']); + // A transaction has one date, so adding up the counts of a budget + // month's dates counts each transaction once + $rows = ReportScope::mergeReportHalves( + ReportScope::toBudgetMonths($direct, $monthStartDay), + ReportScope::toBudgetMonths($split, $monthStartDay), + ['month'], ['income', 'expenses'], ['count'] + ); usort($rows, static fn (array $a, array $b) => strcmp((string)$a['month'], (string)$b['month'])); return array_map(fn (array $row) => [ @@ -269,20 +280,26 @@ public function getCashFlowByMonthByAccount( bool $includeUntagged = true, bool $excludeTransfers = false, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { + $bucket = ReportScope::monthBucketExpr($monthStartDay); [$direct, $split] = $this->reportHalves( $userId, null, $startDate, $endDate, $visibleAccountIds, $excludeTransfers, - function (IQueryBuilder $qb, string $alloc) use ($tagIds, $includeUntagged): void { + function (IQueryBuilder $qb, string $alloc) use ($tagIds, $includeUntagged, $bucket): void { $qb->select('t.account_id') - ->addSelect($qb->createFunction(ReportScope::monthExpr() . ' as month')); + ->addSelect($qb->createFunction($bucket . ' as month')); ReportScope::selectIncomeExpenses($qb, $alloc); $qb->selectAlias($qb->createFunction('COUNT(DISTINCT t.id)'), 'count'); ReportScope::applyTagFilter($qb, $tagIds, $includeUntagged); - $qb->groupBy('t.account_id', $qb->createFunction(ReportScope::monthExpr())); + $qb->groupBy('t.account_id', $qb->createFunction($bucket)); } ); - $rows = ReportScope::mergeReportHalves($direct, $split, ['account_id', 'month'], ['income', 'expenses'], ['count']); + $rows = ReportScope::mergeReportHalves( + ReportScope::toBudgetMonths($direct, $monthStartDay), + ReportScope::toBudgetMonths($split, $monthStartDay), + ['account_id', 'month'], ['income', 'expenses'], ['count'] + ); usort($rows, static fn (array $a, array $b) => strcmp((string)$a['month'], (string)$b['month'])); return array_map(static fn (array $row) => [ @@ -315,13 +332,14 @@ public function getMonthlyTrendData( bool $includeUntagged = true, bool $excludeTransfers = false, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { return array_map(static fn (array $row) => [ 'month' => $row['month'], 'income' => $row['income'], 'expenses' => $row['expenses'], ], $this->getCashFlowByMonth( - $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay )); } @@ -342,6 +360,7 @@ public function getMonthlyTrendDataByAccount( bool $includeUntagged = true, bool $excludeTransfers = false, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { return array_map(static fn (array $row) => [ 'month' => $row['month'], @@ -349,7 +368,7 @@ public function getMonthlyTrendDataByAccount( 'income' => $row['income'], 'expenses' => $row['expenses'], ], $this->getCashFlowByMonthByAccount( - $userId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay )); } @@ -786,6 +805,8 @@ function (IQueryBuilder $qb, string $alloc) use ($tagIds): void { * under key UNCATEGORIZED, so the report's totals match the month view. * * @param int[]|null $visibleAccountIds + * @param int $monthStartDay 1 for calendar months, else budget months + * starting on that day (see getCashFlowByMonth()) * @return array> categoryId => 'YYYY-MM' => net */ public function getCategoryNetByMonth( @@ -794,20 +815,27 @@ public function getCategoryNetByMonth( string $endDate, ?int $accountId = null, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { + $bucket = ReportScope::monthBucketExpr($monthStartDay); [$direct, $split] = $this->reportHalves( $userId, $accountId, $startDate, $endDate, $visibleAccountIds, $accountId === null, - function (IQueryBuilder $qb, string $alloc): void { + function (IQueryBuilder $qb, string $alloc) use ($bucket): void { $qb->select("{$alloc}.category_id") - ->addSelect($qb->createFunction(ReportScope::monthExpr() . ' as month')) + ->addSelect($qb->createFunction($bucket . ' as month')) ->selectAlias($qb->createFunction(ReportScope::signedAmountSum($qb, 'credit', "{$alloc}.amount")), 'net') ->groupBy("{$alloc}.category_id") - ->addGroupBy($qb->createFunction(ReportScope::monthExpr())); + ->addGroupBy($qb->createFunction($bucket)); } ); $totals = []; - foreach (ReportScope::mergeReportHalves($direct, $split, ['category_id', 'month'], ['net']) as $row) { + $merged = ReportScope::mergeReportHalves( + ReportScope::toBudgetMonths($direct, $monthStartDay), + ReportScope::toBudgetMonths($split, $monthStartDay), + ['category_id', 'month'], ['net'] + ); + foreach ($merged as $row) { $catId = $row['category_id'] === null ? self::UNCATEGORIZED : (int)$row['category_id']; $totals[$catId][substr((string)$row['month'], 0, 7)] = $row['net']; } diff --git a/budget/lib/Service/BudgetCarryoverService.php b/budget/lib/Service/BudgetCarryoverService.php index b968d2a8e..3207ca9df 100644 --- a/budget/lib/Service/BudgetCarryoverService.php +++ b/budget/lib/Service/BudgetCarryoverService.php @@ -44,6 +44,9 @@ */ class BudgetCarryoverService { + /** 'calendar' (the default) or 'budget': how the charts and reports cut months */ + public const REPORT_MONTHS_SETTING = 'report_month_grouping'; + /** Hard cap on chain length — keeps multi-year anchors bounded */ private const MAX_CHAIN_MONTHS = 60; @@ -460,6 +463,17 @@ public function budgetStartDay(string $userId): int { return max(1, min(31, $startDay)); } + /** + * The day the months of the dashboard charts and the month-by-month + * reports start on: the budget start day when the user chose budget + * months for them in Settings, otherwise 1, calendar months (#457). + */ + public function reportMonthStartDay(string $userId): int { + return $this->settingService->get($userId, self::REPORT_MONTHS_SETTING) === 'budget' + ? $this->budgetStartDay($userId) + : 1; + } + /** * Today (Y-m-d) on the user's calendar, not the server's: in Sydney the * server is still on last month until mid-morning on the 1st, and the diff --git a/budget/lib/Service/BudgetPeriod.php b/budget/lib/Service/BudgetPeriod.php index bef65bba6..1bb2e20f5 100644 --- a/budget/lib/Service/BudgetPeriod.php +++ b/budget/lib/Service/BudgetPeriod.php @@ -74,6 +74,31 @@ public static function monthContaining(string $date, int $startDay): string { return substr($date, 0, 7); } + /** + * The budget months (Y-m) a range touches, in order: from the one + * holding $start to the one holding $end. With start day 1 these are + * the calendar months. Empty when the range is reversed. + * + * @return list + */ + public static function monthsBetween(string $start, string $end, int $startDay): array { + if ($start > $end) { + return []; + } + $months = []; + $month = \DateTime::createFromFormat('!Y-m', self::monthContaining($start, $startDay)); + $last = self::monthContaining($end, $startDay); + // Bounded: a thousand years of months is more than any range asks for + for ($guard = 0; $guard < 12000; $guard++) { + $months[] = $month->format('Y-m'); + if ($months[count($months) - 1] >= $last) { + break; + } + $month->modify('first day of next month'); + } + return $months; + } + /** * Budget amounts of any periods as one monthly total, by the yearly * ratios the Budget page's summary uses (formatters.prorateBudget): each diff --git a/budget/lib/Service/Report/ReportAggregator.php b/budget/lib/Service/Report/ReportAggregator.php index cf0da33b3..9e71aa96b 100644 --- a/budget/lib/Service/Report/ReportAggregator.php +++ b/budget/lib/Service/Report/ReportAggregator.php @@ -95,6 +95,7 @@ public function generateSummary( array $tagIds = [], bool $includeUntagged = true, array $visibleAccountIds = [], + int $monthStartDay = 1, ): array { if ($accountId) { // One account selected: an account shared with the user is in @@ -383,7 +384,7 @@ public function generateSummary( $summary['spending'] = $this->spendingInBase($userId, $accountId, !empty($visibleAccountIds) ? $visibleAccountIds : null, $spendingQuery); // Generate trend data (with currency conversion for multi-account view) - $summary['trends'] = $this->generateTrendData($userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, !empty($visibleAccountIds) ? $visibleAccountIds : null); + $summary['trends'] = $this->generateTrendData($userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, !empty($visibleAccountIds) ? $visibleAccountIds : null, $monthStartDay); return $summary; } @@ -401,9 +402,10 @@ public function generateSummaryWithComparison( array $tagIds = [], bool $includeUntagged = true, array $visibleAccountIds = [], + int $monthStartDay = 1, ): array { // Current period - $current = $this->generateSummary($userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $visibleAccountIds); + $current = $this->generateSummary($userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $visibleAccountIds, $monthStartDay); // Calculate previous period (same duration) $start = new \DateTime($startDate); @@ -422,7 +424,8 @@ public function generateSummaryWithComparison( $prevEnd->format('Y-m-d'), $tagIds, $includeUntagged, - $visibleAccountIds + $visibleAccountIds, + $monthStartDay ); // Calculate changes @@ -652,6 +655,7 @@ public function getCashFlowReport( array $tagIds = [], bool $includeUntagged = true, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { $excludeTransfers = $accountId === null; @@ -668,18 +672,18 @@ public function getCashFlowReport( if ($needsConversion) { $currencyMap = $this->conversionService->getAccountCurrencyMap($accounts); $cashFlow = $this->convertCashFlowByAccount( - $userId, $startDate, $endDate, $currencyMap, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $startDate, $endDate, $currencyMap, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); } else { $cashFlow = $this->reportQueries->getCashFlowByMonth( - $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); } } else { // Still within the viewer's accounts: without them the query is // scoped to the viewer's own, and a shared account came back empty $cashFlow = $this->reportQueries->getCashFlowByMonth( - $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); } @@ -694,7 +698,7 @@ public function getCashFlowReport( $monthCount = count($cashFlow); return [ - 'period' => ['startDate' => $startDate, 'endDate' => $endDate], + 'period' => ['startDate' => $startDate, 'endDate' => $endDate, 'monthStartDay' => $monthStartDay], 'data' => $cashFlow, 'totals' => $totals, 'averageMonthly' => [ @@ -719,9 +723,10 @@ private function convertCashFlowByAccount( bool $includeUntagged, bool $excludeTransfers, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { $perAccountData = $this->reportQueries->getCashFlowByMonthByAccount( - $userId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); $baseCurrency = $this->conversionService->getBaseCurrency($userId); @@ -769,6 +774,7 @@ public function generateTrendData( array $tagIds = [], bool $includeUntagged = true, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { $excludeTransfers = $accountId === null; @@ -784,11 +790,11 @@ public function generateTrendData( if ($needsConversion) { $currencyMap = $this->conversionService->getAccountCurrencyMap($accounts); $dataByMonth = $this->convertTrendDataByAccount( - $userId, $startDate, $endDate, $currencyMap, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $startDate, $endDate, $currencyMap, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); } else { $monthlyData = $this->reportQueries->getMonthlyTrendData( - $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); $dataByMonth = []; foreach ($monthlyData as $row) { @@ -798,7 +804,7 @@ public function generateTrendData( } else { // Within the viewer's accounts, as getCashFlowReport() does $monthlyData = $this->reportQueries->getMonthlyTrendData( - $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, false, $visibleAccountIds + $userId, $accountId, $startDate, $endDate, $tagIds, $includeUntagged, false, $visibleAccountIds, $monthStartDay ); $dataByMonth = []; foreach ($monthlyData as $row) { @@ -808,29 +814,22 @@ public function generateTrendData( // `months` (Y-m) is what the web UI formats, in the user's own // language; `labels` stays as the English "M Y" for anything that - // still reads it. + // still reads it. With a month start day they are budget months. $trends = [ 'labels' => [], 'months' => [], 'income' => [], - 'expenses' => [] + 'expenses' => [], + 'monthStartDay' => $monthStartDay, ]; - $start = new \DateTime($startDate); - $end = new \DateTime($endDate); - $interval = new \DateInterval('P1M'); - - $current = clone $start; - while ($current <= $end) { - $month = $current->format('Y-m'); - $trends['labels'][] = $current->format('M Y'); + foreach ($this->trendMonths($startDate, $endDate, $monthStartDay) as $month) { + $trends['labels'][] = \DateTime::createFromFormat('!Y-m', $month)->format('M Y'); $trends['months'][] = $month; $monthData = $dataByMonth[$month] ?? ['income' => 0, 'expenses' => 0]; $trends['income'][] = $monthData['income']; $trends['expenses'][] = $monthData['expenses']; - - $current->add($interval); } return $trends; @@ -855,7 +854,7 @@ public function generateTrendData( * * @param string $sort 'alpha' (default) or 'total' * @param int[] $visibleAccountIds - * @return array{period: array, sort: string, baseCurrency: string, rows: array, totals: array} + * @return array{period: array, sort: string, baseCurrency: string, mixedCurrency: bool, rows: array, totals: array} */ public function getCategoryMonthlyReport( string $userId, @@ -864,14 +863,15 @@ public function getCategoryMonthlyReport( ?int $accountId = null, string $sort = 'alpha', array $visibleAccountIds = [], + int $monthStartDay = 1, ): array { $sort = $sort === 'total' ? 'total' : 'alpha'; $vis = !empty($visibleAccountIds) ? $visibleAccountIds : null; - $months = $this->buildMonthList($startDate, $endDate); + $months = $this->buildMonthList($startDate, $endDate, $monthStartDay); // Signed net per category per month: each category's OWN amounts // (direct + split parts), already report-scoped in SQL - $own = $this->reportQueries->getCategoryNetByMonth($userId, $startDate, $endDate, $accountId, $vis); + $own = $this->reportQueries->getCategoryNetByMonth($userId, $startDate, $endDate, $accountId, $vis, $monthStartDay); // Rows: a category excluded from reports, or muted by this viewer, // carries no money (the query dropped it) and is not shown either; @@ -1030,7 +1030,7 @@ public function getCategoryMonthlyReport( $mixedCurrency = $this->conversionService->needsConversion($reportAccounts); return [ - 'period' => ['startDate' => $startDate, 'endDate' => $endDate, 'months' => $months], + 'period' => ['startDate' => $startDate, 'endDate' => $endDate, 'months' => $months, 'monthStartDay' => $monthStartDay], 'sort' => $sort, 'baseCurrency' => $this->conversionService->getBaseCurrency($userId), 'mixedCurrency' => $mixedCurrency, @@ -1040,11 +1040,39 @@ public function getCategoryMonthlyReport( } /** - * List of 'YYYY-MM' month keys from startDate to endDate inclusive. + * The months of a trend series. Calendar months step from the start date + * as they always have; with a month start day they are the budget + * months the range touches. + * + * @return string[] 'YYYY-MM' keys + */ + private function trendMonths(string $startDate, string $endDate, int $monthStartDay): array { + if ($monthStartDay > 1) { + return BudgetPeriod::monthsBetween($startDate, $endDate, $monthStartDay); + } + $months = []; + $current = new \DateTime($startDate); + $end = new \DateTime($endDate); + $interval = new \DateInterval('P1M'); + while ($current <= $end) { + $months[] = $current->format('Y-m'); + $current->add($interval); + } + return $months; + } + + /** + * List of 'YYYY-MM' month keys from startDate to endDate inclusive: + * calendar months, or with a month start day the budget months the + * range touches. * * @return string[] */ - private function buildMonthList(string $startDate, string $endDate): array { + private function buildMonthList(string $startDate, string $endDate, int $monthStartDay = 1): array { + if ($monthStartDay > 1) { + // The same guard as the calendar months below + return array_slice(BudgetPeriod::monthsBetween($startDate, $endDate, $monthStartDay), 0, 600); + } $months = []; $cur = strtotime(substr($startDate, 0, 7) . '-01'); $end = strtotime(substr($endDate, 0, 7) . '-01'); @@ -1097,9 +1125,10 @@ private function convertTrendDataByAccount( bool $includeUntagged, bool $excludeTransfers, ?array $visibleAccountIds = null, + int $monthStartDay = 1, ): array { $perAccountData = $this->reportQueries->getMonthlyTrendDataByAccount( - $userId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds + $userId, $startDate, $endDate, $tagIds, $includeUntagged, $excludeTransfers, $visibleAccountIds, $monthStartDay ); $baseCurrency = $this->conversionService->getBaseCurrency($userId); diff --git a/budget/lib/Service/ReportService.php b/budget/lib/Service/ReportService.php index b2097eb87..c44f191a4 100644 --- a/budget/lib/Service/ReportService.php +++ b/budget/lib/Service/ReportService.php @@ -25,6 +25,7 @@ public function __construct( ReportExporter $exporter, TagReportService $tagReportService, AmountColours $amountColours, + private ?BudgetCarryoverService $carryoverService = null, ) { $this->calculator = $calculator; $this->aggregator = $aggregator; @@ -33,6 +34,15 @@ public function __construct( $this->amountColours = $amountColours; } + /** + * The day the months of the month-by-month figures start on: 1 for + * calendar months, or the budget start day when the user chose budget + * months for the charts and reports (#457). + */ + private function monthStartDay(string $userId): int { + return $this->carryoverService?->reportMonthStartDay($userId) ?? 1; + } + /** * Generate a comprehensive financial summary. * @param int[] $tagIds Optional tag filter (OR logic) @@ -54,7 +64,8 @@ public function generateSummary( $endDate, $tagIds, $includeUntagged, - $visibleAccountIds + $visibleAccountIds, + $this->monthStartDay($userId) ); } @@ -79,7 +90,8 @@ public function generateSummaryWithComparison( $endDate, $tagIds, $includeUntagged, - $visibleAccountIds + $visibleAccountIds, + $this->monthStartDay($userId) ); } @@ -255,7 +267,8 @@ public function getCashFlowReport( $endDate, $tagIds, $includeUntagged, - $visibleAccountIds + $visibleAccountIds, + $this->monthStartDay($userId) ); } @@ -396,7 +409,8 @@ public function getCategoryMonthlyReport( $endDate, $accountId, $sort, - $visibleAccountIds ?? [] + $visibleAccountIds ?? [], + $this->monthStartDay($userId) ); } diff --git a/budget/src/modules/dashboard/DashboardModule.js b/budget/src/modules/dashboard/DashboardModule.js index c9740328f..7b19c2769 100644 --- a/budget/src/modules/dashboard/DashboardModule.js +++ b/budget/src/modules/dashboard/DashboardModule.js @@ -180,12 +180,17 @@ export default class DashboardModule { const periodEnd = currentPeriod.end; const periodMonth = formatters.budgetMonthForCycle(periodStart, periodEnd); - // The trend and spending charts are calendar-month series, so they - // stop at this month's end; a cycle ending next month would add an - // empty bar for it. - const sixMonthsAgoDate = new Date(now.getFullYear(), now.getMonth() - 5, 1); - const sixMonthsAgo = formatters.getMonthStart(sixMonthsAgoDate.getFullYear(), sixMonthsAgoDate.getMonth() + 1); - const endOfMonth = formatters.getMonthEnd(now.getFullYear(), now.getMonth() + 1); + // The trend and spending charts are month series: calendar months, + // or budget months when the user chose them in Settings (#457). + // They cover whole months and stop at the current one's end; a + // calendar series running to a cycle's end in next month would + // add an empty bar for it. + const chartStartDay = formatters.reportMonthStartDay(this.settings); + const chartMonth = formatters.currentBudgetMonth(chartStartDay, now); + const sixMonthsAgo = formatters.budgetMonthRange(formatters.shiftMonth(chartMonth, -5), chartStartDay).start; + const endOfMonth = formatters.budgetMonthRange(chartMonth, chartStartDay).end; + // The hero tiles compare this budget period with the one before + const previousPeriod = formatters.budgetMonthRange(formatters.shiftMonth(periodMonth, -1), budgetStartDay); // Cache-busting timestamp to ensure fresh data const cacheBuster = Date.now(); @@ -202,9 +207,11 @@ export default class DashboardModule { }; // Load all dashboard data in parallel for better performance - const [summary, trendData, transactions, billsRaw, budgetDataRaw, goalsRaw, pensionRaw, assetRaw, netWorthRaw, alertsRaw, debtSummary, assetValueHistory] = await Promise.all([ + const [summary, previousSummary, trendData, transactions, billsRaw, budgetDataRaw, goalsRaw, pensionRaw, assetRaw, netWorthRaw, alertsRaw, debtSummary, assetValueHistory] = await Promise.all([ // Current budget cycle summary for hero stats apiFetch(`/apps/budget/api/reports/summary?startDate=${periodStart}&endDate=${periodEnd}&_=${cacheBuster}`).catch(orEmpty({})), + // The cycle before, for the hero tiles' "vs last month" + apiFetch(`/apps/budget/api/reports/summary?startDate=${previousPeriod.start}&endDate=${previousPeriod.end}&_=${cacheBuster}`).catch(orEmpty({})), // 6-month summary for trend charts apiFetch(`/apps/budget/api/reports/summary?startDate=${sixMonthsAgo}&endDate=${endOfMonth}&_=${cacheBuster}`).catch(orEmpty({})), apiFetch(`/apps/budget/api/transactions?limit=${this._recentTxLimit()}`).catch(orEmpty([])), @@ -228,6 +235,7 @@ export default class DashboardModule { const budgetAlerts = alertsRaw ?? []; // Update Hero Section (current month data) + summary.previousTotals = previousSummary.totals || null; this.updateDashboardHero(summary, pensionSummary, assetSummary); this.updateHeroPeriodHints(budgetStartDay > 1 ? currentPeriod.label : null); @@ -394,18 +402,18 @@ export default class DashboardModule { incomeEl.textContent = this.formatCurrency(totals.totalIncome || 0, currency); } - // Calculate month-over-month change for income + // Calculate month-over-month change for income: this budget period + // against the whole one before. The summary's trend buckets are + // calendar months, which with a start day cut this period in two. + const previous = summary.previousTotals; const incomeChangeEl = document.getElementById('hero-income-change'); - if (incomeChangeEl && summary.trends && summary.trends.income) { - const incomeData = summary.trends.income; - if (incomeData.length >= 2) { - const currentMonth = incomeData[incomeData.length - 1] || 0; - const lastMonth = incomeData[incomeData.length - 2] || 0; - const change = lastMonth > 0 ? ((currentMonth - lastMonth) / lastMonth * 100) : 0; - if (change !== 0) { - incomeChangeEl.innerHTML = `${change >= 0 ? '↑' : '↓'} ${t('budget', '{percent}% vs last month', { percent: Math.abs(change).toFixed(1) })}`; - incomeChangeEl.className = `hero-change ${change >= 0 ? 'positive' : 'negative'}`; - } + if (incomeChangeEl && previous) { + const currentMonth = totals.totalIncome || 0; + const lastMonth = previous.totalIncome || 0; + const change = lastMonth > 0 ? ((currentMonth - lastMonth) / lastMonth * 100) : 0; + if (change !== 0) { + incomeChangeEl.innerHTML = `${change >= 0 ? '↑' : '↓'} ${t('budget', '{percent}% vs last month', { percent: Math.abs(change).toFixed(1) })}`; + incomeChangeEl.className = `hero-change ${change >= 0 ? 'positive' : 'negative'}`; } } @@ -417,17 +425,14 @@ export default class DashboardModule { // Calculate month-over-month change for expenses const expensesChangeEl = document.getElementById('hero-expenses-change'); - if (expensesChangeEl && summary.trends && summary.trends.expenses) { - const expenseData = summary.trends.expenses; - if (expenseData.length >= 2) { - const currentMonth = expenseData[expenseData.length - 1] || 0; - const lastMonth = expenseData[expenseData.length - 2] || 0; - const change = lastMonth > 0 ? ((currentMonth - lastMonth) / lastMonth * 100) : 0; - if (change !== 0) { - // For expenses, down is good - expensesChangeEl.innerHTML = `${change >= 0 ? '↑' : '↓'} ${t('budget', '{percent}% vs last month', { percent: Math.abs(change).toFixed(1) })}`; - expensesChangeEl.className = `hero-change ${change <= 0 ? 'positive' : 'negative'}`; - } + if (expensesChangeEl && previous) { + const currentMonth = totals.totalExpenses || 0; + const lastMonth = previous.totalExpenses || 0; + const change = lastMonth > 0 ? ((currentMonth - lastMonth) / lastMonth * 100) : 0; + if (change !== 0) { + // For expenses, down is good + expensesChangeEl.innerHTML = `${change >= 0 ? '↑' : '↓'} ${t('budget', '{percent}% vs last month', { percent: Math.abs(change).toFixed(1) })}`; + expensesChangeEl.className = `hero-change ${change <= 0 ? 'positive' : 'negative'}`; } } @@ -508,18 +513,14 @@ export default class DashboardModule { el.className = `hero-value ${cashFlow >= 0 ? 'income' : 'expenses'}`; const changeEl = document.getElementById('hero-cash-flow-change'); - if (changeEl && summary.trends) { - // Calculate month-over-month change - const incomeData = summary.trends.income || []; - const expenseData = summary.trends.expenses || []; - if (incomeData.length >= 2 && expenseData.length >= 2) { - const currentCF = (incomeData[incomeData.length - 1] || 0) - (expenseData[expenseData.length - 1] || 0); - const lastCF = (incomeData[incomeData.length - 2] || 0) - (expenseData[expenseData.length - 2] || 0); - const change = lastCF !== 0 ? ((currentCF - lastCF) / Math.abs(lastCF) * 100) : 0; - if (change !== 0) { - changeEl.innerHTML = `${change >= 0 ? '↑' : '↓'} ${t('budget', '{percent}% vs last month', { percent: Math.abs(change).toFixed(1) })}`; - changeEl.className = `hero-change ${change >= 0 ? 'positive' : 'negative'}`; - } + const previous = summary.previousTotals; + if (changeEl && previous) { + // This budget period against the whole one before + const lastCF = (previous.totalIncome || 0) - (previous.totalExpenses || 0); + const change = lastCF !== 0 ? ((cashFlow - lastCF) / Math.abs(lastCF) * 100) : 0; + if (change !== 0) { + changeEl.innerHTML = `${change >= 0 ? '↑' : '↓'} ${t('budget', '{percent}% vs last month', { percent: Math.abs(change).toFixed(1) })}`; + changeEl.className = `hero-change ${change >= 0 ? 'positive' : 'negative'}`; } } } @@ -3041,6 +3042,11 @@ export default class DashboardModule { this.charts[instanceId].destroy(); } + const card = this.isDuplicateInstance(instanceId) + ? this.getWidgetCard(instanceId) + : document.getElementById('trend-chart-card'); + formatters.showMonthGroupingNote(card?.querySelector('.month-grouping-note'), trends?.monthStartDay || 1); + if (!trends || !trends.labels || trends.labels.length === 0) return; const ctx = canvas.getContext('2d'); @@ -3055,8 +3061,9 @@ export default class DashboardModule { // user's language; `labels` is its English "M Y", kept for older servers. const months = Array.isArray(trends.months) && trends.months.length === trends.labels.length ? trends.months : null; const labels = months ? months.map(m => formatters.formatYearMonth(m)) : trends.labels; - const now = new Date(); - const thisMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`; + // With budget months (#457) the month in progress is the budget month + const monthStartDay = trends.monthStartDay || 1; + const thisMonth = formatters.currentBudgetMonth(monthStartDay); const lastIndex = trends.labels.length - 1; const partialIndex = months && months[lastIndex] === thisMonth ? lastIndex : -1; const partialSegment = { @@ -3669,10 +3676,19 @@ export default class DashboardModule { async refreshTrendChart(months, accountId = null, instanceId = 'trendChart') { try { - const startDate = new Date(); - startDate.setMonth(startDate.getMonth() - months); + const chartStartDay = formatters.reportMonthStartDay(this.settings); + let startDate; + if (chartStartDay > 1) { + // Whole budget months (#457), as the dashboard loads them + const chartMonth = formatters.currentBudgetMonth(chartStartDay); + startDate = formatters.budgetMonthRange(formatters.shiftMonth(chartMonth, -months), chartStartDay).start; + } else { + const start = new Date(); + start.setMonth(start.getMonth() - months); + startDate = formatters.formatDateForAPI(start); + } - let url = `/apps/budget/api/reports/summary?startDate=${formatters.formatDateForAPI(startDate)}`; + let url = `/apps/budget/api/reports/summary?startDate=${startDate}`; if (accountId) { url += `&accountId=${accountId}`; } diff --git a/budget/src/modules/reports/ReportsModule.js b/budget/src/modules/reports/ReportsModule.js index 42be2a0f3..2e7b53d83 100644 --- a/budget/src/modules/reports/ReportsModule.js +++ b/budget/src/modules/reports/ReportsModule.js @@ -744,6 +744,7 @@ export default class ReportsModule { renderReportTrendChart(trends) { const canvas = document.getElementById('report-trend-chart'); if (!canvas || !trends) return; + formatters.showMonthGroupingNote(document.getElementById('report-trend-month-note'), trends.monthStartDay || 1); if (this.reportCharts.trend) { this.reportCharts.trend.destroy(); @@ -1052,6 +1053,7 @@ export default class ReportsModule { if (avgNetEl) avgNetEl.textContent = this.formatCurrency(averages.net || 0, currency); // Render chart + formatters.showMonthGroupingNote(document.getElementById('report-cashflow-month-note'), data.period?.monthStartDay || 1); this.renderCashFlowChart(data.data || []); // Render table @@ -1069,6 +1071,7 @@ export default class ReportsModule { const sortSel = document.getElementById('category-monthly-sort'); if (sortSel && sortSel.value !== sort) sortSel.value = sort; + formatters.showMonthGroupingNote(document.getElementById('category-monthly-month-note'), data.period?.monthStartDay || 1); this.renderCategoryMonthlyMatrix(data); } diff --git a/budget/src/utils/formatters.js b/budget/src/utils/formatters.js index 24d3cb550..4d7a1f64b 100644 --- a/budget/src/utils/formatters.js +++ b/budget/src/utils/formatters.js @@ -554,6 +554,36 @@ export function currentBudgetMonth(startDay = 1, referenceDate = null) { return budgetMonthForCycle(cycle.start, cycle.end); } +/** + * The day the months of the dashboard charts and the month-by-month reports + * start on: the budget start day when the user chose budget months for them + * in Settings, otherwise 1, calendar months (#457). As + * BudgetCarryoverService::reportMonthStartDay on the server. + * + * @param {object} settings - The user's settings + * @returns {number} 1-31 + */ +export function reportMonthStartDay(settings) { + if (settings?.report_month_grouping !== 'budget') return 1; + const startDay = parseInt(settings?.budget_start_day || '1', 10); + return Number.isFinite(startDay) ? Math.min(31, Math.max(1, startDay)) : 1; +} + +/** + * Show or hide a note saying a chart's or report's months are budget months. + * + * @param {HTMLElement|null} el - The note element + * @param {number} monthStartDay - As reportMonthStartDay(); 1 hides the note + */ +export function showMonthGroupingNote(el, monthStartDay) { + if (!el) return; + const budgetMonths = monthStartDay > 1; + el.textContent = budgetMonths + ? t('budget', 'Months are budget months starting on day {day}, as chosen in Settings.', { day: monthStartDay }) + : ''; + el.style.display = budgetMonths ? '' : 'none'; +} + /** * The dates a budget month covers: the calendar month, or with a budget start * day the cycle holding the month's 15th. diff --git a/budget/templates/index.php b/budget/templates/index.php index 6af1afcd5..7d9c1745c 100644 --- a/budget/templates/index.php +++ b/budget/templates/index.php @@ -605,6 +605,7 @@ class="app-navigation-search-clear icon-close"
+ @@ -3328,6 +3329,7 @@ class="app-navigation-search-clear icon-close"
+ @@ -3491,6 +3493,7 @@ class="app-navigation-search-clear icon-close"
+ @@ -3713,6 +3716,7 @@ class="app-navigation-search-clear icon-close"

t('Income is shown positive, expenses negative. Parent categories include the totals of their sub-categories.')); ?>

+
@@ -4469,6 +4473,17 @@ class="app-navigation-search-clear icon-close" min="1" max="31" step="1" value="1"> +
+ + +
+
\n
\n \n
\n
\n ')},spendingChart:function(t,e){return'\n
\n

'.concat(e.name,'

\n
\n
\n
\n
\n \n
\n
\n
\n ')},netWorthHistory:function(t,e){return'\n
\n

'.concat(e.name,'

\n
\n
\n \n
\n \n
\n \n ")},assetValueHistory:function(t,e){return'\n
\n

'.concat(e.name,'

\n
\n
\n
\n \n
\n \n ")},recentTransactions:function(t,e){return'\n
\n
\n ')}}}},{key:"_wrapCardsForGridstack",value:function(t){var e;t.classList.add("grid-stack");var n=(null===(e=this.dashboardConfig.widgets)||void 0===e?void 0:e.visibility)||{},a=document.getElementById("hidden-widgets");Array.from(t.querySelectorAll('[data-widget-category="widget"]')).forEach(function(t){if(!t.closest(".grid-stack-item")){var e=t.dataset.widgetId,r=["budgetAlerts","debtPayoff","debtChart","debtProgress","projects"].includes(e),i=(!0===n[e]||void 0===n[e]&&"none"!==t.style.display)&&!(r&&"none"===t.style.display),o=document.createElement("div");o.className="grid-stack-item",o.setAttribute("gs-id",e);var s=document.createElement("div");s.className="grid-stack-item-content",t.parentNode.insertBefore(o,t),s.appendChild(t),o.appendChild(s),i||(o.style.display="none",a&&a.appendChild(o))}})}},{key:"_computeInitialPositions",value:function(){var t,e,n,a=(null===(t=this.dashboardConfig.widgets)||void 0===t?void 0:t.visibility)||{},r=Object.values(a).filter(function(t){return!1!==t}).length,i=null===(e=this.dashboardConfig.widgets)||void 0===e?void 0:e.positions;if(i&&Object.keys(i).length>0){var o=Object.keys(i).filter(function(t){return!1!==a[t]}).length;if(o>=.8*r){for(var s=0,c=Object.entries(a);sp&&(y+=4,v=0),m[w]={x:v,y,w:E,h:x},(v+=E)>=p&&(v=0,y+=x)}}}catch(t){b.e(t)}finally{b.f()}return m}},{key:"initGridstack",value:function(){var t=this,e=document.querySelector(".dashboard-grid");if(e&&!this.gridstack){this._wrapCardsForGridstack(e);var n=this._computeInitialPositions();this.gridstack=xt.init({column:this.gridColumns||3,cellHeight:100,margin:10,float:!1,animate:!0,disableOneColumnMode:!0,disableResize:!0,staticGrid:!1},e),this._tilesDraggable()||this.gridstack.disable();for(var a=[],r=0,i=Object.entries(n);r2?(e.dataset.fullH=String(n.h),t.gridstack.update(e,{h:2})):!r&&e.dataset.fullH&&(t.gridstack.update(e,{h:parseInt(e.dataset.fullH,10)}),delete e.dataset.fullH)}}),this.gridstack.batchUpdate(!1)}finally{this._compactingTiles=!1}requestAnimationFrame(function(){return t.resizeAllCharts()})}}},{key:"_isTileEmpty",value:function(t){var e=function(t){return t.getClientRects().length>0};if(0===Ft(t.querySelectorAll(".empty-state-small, .chart-empty-state")).filter(e).length)return!1;if(Ft(t.querySelectorAll("canvas")).some(e))return!1;for(var n=document.createTreeWalker(t,NodeFilter.SHOW_TEXT),a=n.nextNode();a;a=n.nextNode())if(a.textContent.trim()){var r=a.parentElement;if(r&&e(r)&&!r.closest(".card-header, .empty-state-small, .chart-empty-state, .widget-tile-controls"))return!1}return!0}},{key:"_saveGridstackPositions",value:function(){if(this.gridstack){var t={};if(this.gridstack.getGridItems().forEach(function(e){var n=e.getAttribute("gs-id");if(n){var a=e.gridstackNode;if(a){var r=e.dataset.fullH?parseInt(e.dataset.fullH,10):a.h;t[n]={x:a.x,y:a.y,w:a.w,h:r}}}}),this.dashboardConfig.widgets||(this.dashboardConfig.widgets={}),this._gridNarrowed()||(this.dashboardConfig.widgets.positions=t),Object.keys(t).length>0){var e=Object.entries(t).sort(function(t,e){var n=Nt(t,2)[1],a=Nt(e,2)[1];return n.y-a.y||n.x-a.x}).map(function(t){return Nt(t,1)[0]}),n=(this.dashboardConfig.widgets.order||[]).filter(function(t){return!e.includes(t)});this.dashboardConfig.widgets.order=[].concat(Ft(e),Ft(n))}this.saveDashboardVisibility("widgets")}}},{key:"_updateFullWidthTiles",value:function(t){var e,n=this;if(this.gridstack){var a=(null===(e=this.dashboardConfig.widgets)||void 0===e?void 0:e.sizes)||{};this.gridstack.getGridItems().forEach(function(e){var r=e.getAttribute("gs-id");r&&"l"===a[r]&&n.gridstack.update(e,{w:t})})}}},{key:"setupHeroDragAndDrop",value:function(){var t=this,e=document.querySelector(".dashboard-hero");e&&e.querySelectorAll('[data-widget-category="hero"]').forEach(function(n){n.setAttribute("draggable","true"),n.style.cursor="move",n.addEventListener("dragstart",function(e){t._heroDragItem=n,n.classList.add("hero-dragging"),e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",n.dataset.widgetId)}),n.addEventListener("dragend",function(){n.classList.remove("hero-dragging"),e.querySelectorAll('[data-widget-category="hero"]').forEach(function(t){t.classList.remove("hero-drag-over")}),t._heroDragItem=null}),n.addEventListener("dragover",function(e){e.preventDefault(),e.dataTransfer.dropEffect="move",t._heroDragItem&&t._heroDragItem!==n&&n.classList.add("hero-drag-over")}),n.addEventListener("dragleave",function(){n.classList.remove("hero-drag-over")}),n.addEventListener("drop",function(a){if(a.preventDefault(),n.classList.remove("hero-drag-over"),t._heroDragItem&&t._heroDragItem!==n){var r=Array.from(e.querySelectorAll('[data-widget-category="hero"]'));r.indexOf(t._heroDragItem)1&&void 0!==arguments[1]?arguments[1]:{}).account,a=void 0===n||n,r=(null===(e=this.dashboardConfig)||void 0===e||null===(e=e.widgets)||void 0===e||null===(e=e.tileSettings)||void 0===e?void 0:e[t])||{},i="";if(a){var o=this._validAccountId(r.accountId);o&&(i+="&accountId=".concat(o))}return r.excludeShared&&(i+="&excludeShared=1"),i}},{key:"needsLazyLoad",value:function(t){return!["savingsRate","cashFlow","budgetRemaining","budgetHealth","topCategories","accountPerformance","budgetBreakdown","goalsSummary","paymentBreakdown","reconciliationStatus"].includes(t)}},{key:"loadWidgetData",value:(a=Zt(zt().m(function t(e){var n,a,r,i,s,c,l,u,d,h,g,p,f,m,v,y,b,w,k,E,x,S,C,I,A,_,M,D,B,L,P,O,F,R,N,j,H,z,V,q,W,U,G,Z=arguments;return zt().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=Z.length>1&&void 0!==Z[1]&&Z[1],!this.widgetDataLoaded[e]||n){t.n=1;break}return t.a(2);case 1:t.p=1,U=e,t.n="uncategorizedCount"===U?2:"monthlyComparison"===U?4:"largeTransactions"===U?6:"pensionProjection"===U?8:"cashFlowForecast"===U?10:"yoyComparison"===U?12:"incomeTracking"===U?14:"daysUntilDebtFree"===U?16:"debtChart"===U?18:"debtProgress"===U?20:"recentImports"===U?22:"ruleEffectiveness"===U?24:"weeklyTrend"===U?26:"unmatchedTransfers"===U?28:"billsDueSoon"===U?30:"categoryTrends"===U?32:"spendingVelocity"===U?34:36;break;case 2:return t.n=3,(0,T.n)("/apps/budget/api/transactions/uncategorized?limit=100");case 3:return this.widgetData.uncategorizedCount=t.v,t.a(3,36);case 4:return r=parseInt((null===(a=this.settings)||void 0===a?void 0:a.budget_start_day)||"1",10),i=o.J$(r),s=o.JX(i,r),c=o.JX(o.Ds(i,-1),r),l=this._tileScopeParams("monthlyComparison"),t.n=5,Promise.all([(0,T.n)("/apps/budget/api/reports/summary?startDate=".concat(s.start,"&endDate=").concat(s.end).concat(l)),(0,T.n)("/apps/budget/api/reports/summary?startDate=".concat(c.start,"&endDate=").concat(c.end).concat(l))]);case 5:return u=t.v,d=Nt(u,2),h=d[0],g=d[1],this.widgetData.monthlyComparison={current:h,previous:g,periodLabel:r>1?s.label:null},t.a(3,36);case 6:return p=this._tileRangeParams(e),t.n=7,(0,T.n)("/apps/budget/api/transactions?limit=10&sort=amount&dateFrom=".concat(p.startDate,"&dateTo=").concat(p.endDate).concat(this._tileScopeParams(e)));case 7:return this.widgetData.largeTransactions=t.v,t.a(3,36);case 8:return t.n=9,(0,T.n)("/apps/budget/api/pensions/projection").catch(function(t){if(t instanceof T.h)return null;throw t});case 9:return this.widgetData.pensionProjection=t.v,t.a(3,36);case 10:return f=this._tileNumberSetting(e,"forecastMonths",o.CZ,6),t.n=11,(0,T.n)("/apps/budget/api/forecast/live?forecastMonths=".concat(f).concat(this._tileScopeParams(e,{account:!1})));case 11:return this.widgetData.cashFlowForecast=t.v,t.a(3,36);case 12:return m=this._tileNumberSetting(e,"yearsToCompare",o.rG,2),t.n=13,(0,T.n)("/apps/budget/api/yoy/years?years=".concat(m).concat(this._tileScopeParams(e)));case 13:return this.widgetData.yoyComparison=t.v,t.a(3,36);case 14:return y=this._validAccountId(null===(v=this.dashboardConfig)||void 0===v||null===(v=v.widgets)||void 0===v||null===(v=v.tileSettings)||void 0===v||null===(v=v.incomeTracking)||void 0===v?void 0:v.accountId),t.n=15,Promise.all([(0,T.n)("/apps/budget/api/recurring-income/summary".concat(y?"?accountId=".concat(y):"")),(0,T.n)("/apps/budget/api/recurring-income?activeOnly=true")]);case 15:return b=t.v,w=Nt(b,2),k=w[0],E=w[1],this.widgetData.incomeTracking={summary:k,incomes:(Array.isArray(E)?E:[]).filter(function(t){return!1!==t.isActive}).filter(function(t){return!y||String(t.accountId)===String(y)})},t.a(3,36);case 16:return t.n=17,(0,T.n)("/apps/budget/api/debts/payoff-plan?strategy=avalanche");case 17:return this.widgetData.daysUntilDebtFree=t.v,t.a(3,36);case 18:return t.n=19,this.renderDebtChartWidget();case 19:return t.a(3,36);case 20:return t.n=21,this.renderDebtProgressWidget();case 21:return t.a(3,36);case 22:return t.n=23,(0,T.n)("/apps/budget/api/import/history?limit=5").catch(function(t){if(t instanceof T.h)return[];throw t});case 23:return this.widgetData.recentImports=t.v,t.a(3,36);case 24:return t.n=25,(0,T.n)("/apps/budget/api/import-rules");case 25:return this.widgetData.ruleEffectiveness=t.v,t.a(3,36);case 26:return S=this._tileRangeParams(e),t.n=27,(0,T.n)("/apps/budget/api/reports/summary?startDate=".concat(S.startDate,"&endDate=").concat(S.endDate).concat(this._tileScopeParams(e)));case 27:return C=t.v,I=o.X6(S.startDate,S.endDate)+1,this.widgetData.weeklyTrend=[{total:(null===(x=C.totals)||void 0===x?void 0:x.totalExpenses)||0,days:I}],t.a(3,36);case 28:return t.n=29,(0,T.n)("/apps/budget/api/transactions?limit=10&unmatched=true");case 29:return A=t.v,this.widgetData.unmatchedTransfers=Array.isArray(A)?A:[],t.a(3,36);case 30:return t.n=31,(0,T.n)("/apps/budget/api/bills?activeOnly=true");case 31:return this.widgetData.billsDueSoon=t.v,t.a(3,36);case 32:return _=this._tileRangeParams(e),M={start:_.startDate,end:_.endDate},D=o.gg(_.startDate,_.endDate),B=this._tileScopeParams("categoryTrends",{account:!1}),t.n=33,Promise.all([(0,T.n)("/apps/budget/api/categories/spending?startDate=".concat(M.start,"&endDate=").concat(M.end).concat(B)),(0,T.n)("/apps/budget/api/categories/spending?startDate=".concat(D.start,"&endDate=").concat(D.end).concat(B))]);case 33:return L=t.v,P=Nt(L,2),O=P[0],F=P[1],R={},Array.isArray(F)&&F.forEach(function(t){R[t.categoryId]=parseFloat(t.spent||0)}),N=new Set((this.app.categories||[]).filter(function(t){return"income"===t.type}).map(function(t){return Number(t.id)})),this.widgetData.categoryTrends=(Array.isArray(O)?O:[]).filter(function(t){return!N.has(Number(t.categoryId))}).map(function(t){return{name:t.name,color:t.color,currentTotal:parseFloat(t.spent||0),previousTotal:R[t.categoryId]||0}}).filter(function(t){return t.currentTotal>0||t.previousTotal>0}).sort(function(t,e){return e.currentTotal-t.currentTotal}),t.a(3,36);case 34:return j=new Date,H=o.Jq(j.getFullYear(),j.getMonth()+1),z=o.JV(j),V=j.getDate(),t.n=35,(0,T.n)("/apps/budget/api/reports/summary?startDate=".concat(H,"&endDate=").concat(z));case 35:return q=t.v,W=parseFloat(q.totalExpenses||0),this.widgetData.spendingVelocity={dailyRate:V>0?W/V:0},t.a(3,36);case 36:this.widgetDataLoaded[e]=!0,t.n=38;break;case 37:t.p=37,G=t.v,console.error("Failed to load data for ".concat(e,":"),G);case 38:return t.a(2)}},t,this,[[1,37]])})),function(t){return a.apply(this,arguments)})},{key:"setupDashboardCustomization",value:function(){var t,e=this,n=document.getElementById("toggle-dashboard-lock-btn");if(n){var a="false"!==this.settings.dashboard_locked;this.app.dashboardLocked=a,this.gridColumns=parseInt(null===(t=this.app.settings)||void 0===t?void 0:t.dashboard_grid_columns)||3,this.updateDashboardLockUI(),n.addEventListener("click",function(){return e.toggleDashboardLock()});var r=document.getElementById("add-tiles-btn"),i=document.getElementById("add-tiles-menu");r&&i&&(r.addEventListener("click",function(t){t.stopPropagation();var e="none"!==i.style.display;i.style.display=e?"none":"block"}),document.addEventListener("click",function(t){r.contains(t.target)||i.contains(t.target)||(i.style.display="none")})),this.setupColumnPicker(),this.setupAccountsTileConfig()}}},{key:"setupColumnPicker",value:function(){var t=this,e=document.getElementById("dashboard-columns-picker");e&&e.querySelectorAll(".columns-btn").forEach(function(n){n.classList.toggle("active",parseInt(n.dataset.cols)===t.gridColumns),n.onclick=function(){var a=parseInt(n.dataset.cols);t.gridColumns=a,e.querySelectorAll(".columns-btn").forEach(function(t){return t.classList.remove("active")}),n.classList.add("active"),t._saveSettings({dashboard_grid_columns:a.toString()}),t.gridstack&&t._applyResponsiveColumns(),requestAnimationFrame(function(){return t.resizeAllCharts()})}})}},{key:"_tilesDraggable",value:function(){var t,e;return!(this.dashboardLocked||null!==(t=(e=window).matchMedia)&&void 0!==t&&t.call(e,"(hover: none)").matches)}},{key:"toggleDashboardLock",value:(n=Zt(zt().m(function t(){var e;return zt().w(function(t){for(;;)switch(t.p=t.n){case 0:return this.app.dashboardLocked=!this.app.dashboardLocked,this.updateDashboardLockUI(),this.gridstack&&(this._tilesDraggable()?this.gridstack.enable():this.gridstack.disable()),this._tilesDraggable()?this.setupHeroDragAndDrop():this.teardownHeroDragAndDrop(),t.p=1,t.n=2,this._saveSettings({dashboard_locked:this.app.dashboardLocked.toString()});case 2:t.n=4;break;case 3:t.p=3,e=t.v,console.error("Failed to save lock state:",e),(0,c.Qg)((0,i.Tl)("budget","Failed to save dashboard lock state"));case 4:return t.a(2)}},t,this,[[1,3]])})),function(){return n.apply(this,arguments)})},{key:"updateDashboardLockUI",value:function(){var t,e=document.getElementById("toggle-dashboard-lock-btn"),n=document.getElementById("lock-btn-text"),a=document.getElementById("dashboard-hint"),r=document.getElementById("lock-btn-icon"),o=document.getElementById("add-tiles-dropdown");if(e&&n&&a){null===(t=document.getElementById("dashboard-view"))||void 0===t||t.classList.toggle("dashboard-locked",!!this.dashboardLocked),a.style.display=this.dashboardLocked?"none":"",n.classList.toggle("visually-hidden",!!this.dashboardLocked);var s=this.dashboardLocked?(0,i.Tl)("budget","Unlock Dashboard"):(0,i.Tl)("budget","Lock Dashboard");e.setAttribute("aria-label",s),e.title=s;var c=document.getElementById("dashboard-columns-picker");if(this.dashboardLocked){n.textContent=(0,i.Tl)("budget","Unlock Dashboard"),a.querySelector("span:last-child").textContent=(0,i.Tl)("budget","Dashboard is locked. Click unlock to reorder tiles."),r&&(r.innerHTML=''),o&&(o.style.display="none"),c&&(c.style.display="none"),document.querySelectorAll(".tile-settings-btn").forEach(function(t){return t.style.display="none"});var l=document.getElementById("tile-settings-modal");l&&(l.style.display="none"),document.querySelectorAll(".widget-tile-controls").forEach(function(t){return t.remove()}),document.querySelectorAll(".card-select, .card-header-controls .period-selector").forEach(function(t){return t.style.display="none"})}else{var u,d;n.textContent=(0,i.Tl)("budget","Lock Dashboard"),a.querySelector("span:last-child").textContent=null!==(u=(d=window).matchMedia)&&void 0!==u&&u.call(d,"(hover: none)").matches?(0,i.Tl)("budget","Use the arrows on each tile to reorder your dashboard"):(0,i.Tl)("budget","Drag tiles to reorder your dashboard"),r&&(r.innerHTML=''),o&&(o.style.display="block"),c&&(c.style.display="flex"),document.querySelectorAll(".tile-settings-btn").forEach(function(t){return t.style.display=""}),document.querySelectorAll(".card-select, .card-header-controls .period-selector").forEach(function(t){return t.style.display="none"}),this.addTileControls()}this.updateAddTilesMenu(),this._compactEmptyTiles()}}},{key:"addTileControls",value:function(){var t=this;document.querySelectorAll(".widget-tile-controls").forEach(function(t){return t.remove()});var e=function(e,n){var a=e.dataset.widgetId;if(a){var r=document.createElement("div");r.className="widget-tile-controls";var o=t.findWidgetDef(a),s=null==o?void 0:o.allowedSizes;if(s&&s.length>1){var c="hero"===n?"hero":"widgets",l=t.getWidgetSize(a,c),u=document.createElement("div");u.className="tile-size-picker",s.forEach(function(n){var r=document.createElement("button");r.className="size-btn ".concat(n===l?"active":""),r.dataset.size=n,r.textContent=n.toUpperCase(),r.title={xs:(0,i.Tl)("budget","Extra small"),s:(0,i.Tl)("budget","Small"),m:(0,i.Tl)("budget","Medium"),l:(0,i.Tl)("budget","Large")}[n],r.setAttribute("aria-label",r.title),r.setAttribute("aria-pressed",n===l?"true":"false"),r.onclick=function(i){i.stopPropagation(),t.changeTileSize(a,n,e),u.querySelectorAll(".size-btn").forEach(function(t){t.classList.remove("active"),t.setAttribute("aria-pressed","false")}),r.classList.add("active"),r.setAttribute("aria-pressed","true")},u.appendChild(r)}),r.appendChild(u);var d=document.createElement("div");d.className="tile-controls-divider",r.appendChild(d)}[[-1,(0,i.Tl)("budget","Move earlier"),"←"],[1,(0,i.Tl)("budget","Move later"),"→"]].forEach(function(a){var i=Nt(a,3),o=i[0],s=i[1],c=i[2],l=document.createElement("button");l.type="button",l.className="tile-move-btn",l.dataset.direction=String(o),l.textContent=c,l.title=s,l.setAttribute("aria-label",s),l.onclick=function(a){a.stopPropagation(),"hero"===n?t.moveHeroTile(e,o):t.moveGridTile(e,o),l.focus()},r.appendChild(l)});var h=document.createElement("div");if(h.className="tile-controls-divider",r.appendChild(h),"hero"!==n){var g=document.createElement("button");g.className="tile-gear-btn",g.innerHTML='',g.title=(0,i.Tl)("budget","Tile Settings"),g.setAttribute("aria-label",g.title),g.onclick=function(e){e.stopPropagation(),t.openTileSettingsModal(a,n)},r.appendChild(g);var p=document.createElement("div");p.className="tile-controls-divider",r.appendChild(p)}var f=document.createElement("button");f.className="widget-remove-btn",f.innerHTML="×",f.title=t.isDuplicateInstance(a)?(0,i.Tl)("budget","Remove tile"):(0,i.Tl)("budget","Hide tile"),f.setAttribute("aria-label",f.title),f.onclick=function(e){e.stopPropagation(),t.isDuplicateInstance(a)?t.removeWidgetInstance(a):t.hideWidget(a,"widget"===n?"widgets":"hero")},r.appendChild(f),e.style.position="relative",e.prepend(r)}};document.querySelectorAll(".hero-card").forEach(function(t){return e(t,"hero")}),document.querySelectorAll(".dashboard-card").forEach(function(t){return e(t,"widget")})}},{key:"findWidgetDef",value:function(t){for(var e=this.getWidgetType(t),n=0,a=["hero","widgets"];n'.concat((0,i.Tl)("budget","All Accounts"),"");this.accounts&&this.accounts.forEach(function(t){x+='")}),y.push('\n
\n \n \n
\n "))}if(l.excludeShared&&Array.isArray(this.accounts)&&this.accounts.some(function(t){return t._shared})){var S=d.excludeShared||!1;y.push('\n
\n \n
\n "))}for(var C=0,I=[this._excludeSharedBillsField(l,d),this._showAllOverdueField(l,d)];C\n \n \n "))}if(l.topLevelOnly){var M=d.topLevelOnly||!1;y.push('\n
\n \n \n
\n "))}if(l.chartType&&Array.isArray(l.chartType)){var D=d.chartType||l.chartType[0],B=l.chartType.map(function(t){var e=t.charAt(0).toUpperCase()+t.slice(1);return'")}).join("");y.push('\n
\n \n \n
\n "))}if(l.rowCount){var L=d.rowCount||l.rowCount.default||5;y.push('\n
\n \n \n
\n '))}if(l.displayFormat&&Array.isArray(l.displayFormat)){var P=d.displayFormat||l.displayFormat[0],O=l.displayFormat.map(function(t){var e=t.charAt(0).toUpperCase()+t.slice(1);return'")}).join("");y.push('\n
\n \n \n
\n "))}if(l.showChangeIndicator){var F=!1!==d.showChangeIndicator;y.push('\n
\n \n
\n "))}var R=["accounts","budgetAlerts"].includes(t);if(f&&(y.length>0?f.innerHTML=y.join(""):R||(f.innerHTML='

'.concat((0,i.Tl)("budget","No settings available for this tile."),"

"))),"accounts"===t&&(m&&(m.innerHTML='

'.concat((0,i.Tl)("budget","Drag to reorder. Toggle visibility for each item."),"

")),this.renderAccountsTileConfigList()),"budgetAlerts"===t){if(m){var N=this.getBudgetAlertFilter().scope;m.innerHTML='\n
\n \n

').concat((0,i.Tl)("budget","Leaves out the budgets worked out from your bills and recurring income."),'

\n

').concat((0,i.Tl)("budget","Untick a category to stop it alerting, here and in notifications."),"

\n
\n ");var j=document.getElementById("budget-alerts-own-budgets-only");j&&(j.onchange=function(){a.saveBudgetAlertFilter({scope:j.checked?"manual":"all"})})}this.renderBudgetAlertsTileConfigList()}l.categoryPicker&&(m&&(m.innerHTML='\n
\n \n

').concat((0,i.Tl)("budget","Untick a category to leave it off this tile, along with its subcategories. Reports and totals still count it."),"

\n
\n ")),this.renderSpendingTileCategoryList(t)),r.querySelectorAll(".tile-setting-input").forEach(function(e){e.onchange=function(){a.saveTileSetting(t,u,e)}});var H=document.getElementById("tile-settings-close");H&&(H.onclick=function(){r.style.display="none",r.setAttribute("aria-hidden","true")}),r.style.display="",r.setAttribute("aria-hidden","false")}}},{key:"saveTileSetting",value:function(t,e,n){var a,r=n.dataset.setting;a="checkbox"===n.type?n.checked:"number"===n.type?parseInt(n.value)||0:n.value,this.dashboardConfig[e].tileSettings||(this.dashboardConfig[e].tileSettings={}),this.dashboardConfig[e].tileSettings[t]||(this.dashboardConfig[e].tileSettings[t]={}),this.dashboardConfig[e].tileSettings[t][r]=a,this.saveDashboardVisibility(),this.refreshTileAfterSettingsChange(t,e),"dateRange"===r?this.updateTilePeriodIndicators():"accountId"===r&&this.updateTileAccountIndicators()}},{key:"refreshTileAfterSettingsChange",value:function(t,e){var n=this,a=this.getWidgetType(t);if(Kt.includes(a))return this.refreshWidgetInstance(t);var r={upcomingBills:function(){var t;return null===(t=n.updateUpcomingBillsWidget)||void 0===t?void 0:t.call(n)},accounts:function(){return n.updateAccountsWidget(n._allDashboardAccounts)},budgetProgress:function(){return n.refreshBudgetProgressWidget(t)},topCategories:function(){return n.refreshTopCategoriesWidget(t)},budgetAlerts:function(){return n.refreshBudgetAlertsWidget()},savingsGoals:function(){var t;return null===(t=n.updateSavingsGoalsWidget)||void 0===t?void 0:t.call(n)},projects:function(){return n.loadProjectsWidget()},debtPayoff:function(){var t;return null===(t=n.updateDebtPayoffWidget)||void 0===t?void 0:t.call(n)},debtChart:function(){return n.renderDebtChartWidget()},debtProgress:function(){return n.renderDebtProgressWidget()},monthlyComparison:function(){return n.loadWidgetData("monthlyComparison",!0).then(function(){var t;return null===(t=n.updateMonthlyComparisonWidget)||void 0===t?void 0:t.call(n)})},largeTransactions:function(){return n.loadWidgetData("largeTransactions",!0).then(function(){var t;return null===(t=n.updateLargeTransactionsWidget)||void 0===t?void 0:t.call(n)})},pensionProjection:function(){var t;return null===(t=n.updatePensionProjectionWidget)||void 0===t?void 0:t.call(n)},weeklyTrend:function(){return n.loadWidgetData("weeklyTrend",!0).then(function(){var t;return null===(t=n.updateWeeklyTrendWidget)||void 0===t?void 0:t.call(n)})},categoryTrends:function(){return n.loadWidgetData("categoryTrends",!0).then(function(){var t;return null===(t=n.updateCategoryTrendsWidget)||void 0===t?void 0:t.call(n)})},billsDueSoon:function(){var t;return null===(t=n.updateBillsDueSoonWidget)||void 0===t?void 0:t.call(n)},incomeTracking:function(){return n.loadWidgetData("incomeTracking",!0).then(function(){var t;return null===(t=n.updateIncomeTrackingWidget)||void 0===t?void 0:t.call(n)})},cashFlowForecast:function(){return n.loadWidgetData("cashFlowForecast",!0).then(function(){var t;return null===(t=n.updateCashFlowForecastWidget)||void 0===t?void 0:t.call(n)})},yoyComparison:function(){return n.loadWidgetData("yoyComparison",!0).then(function(){var t;return null===(t=n.updateYoyComparisonWidget)||void 0===t?void 0:t.call(n)})},accountIncome:function(){var t;return null===(t=n.updateAccountIncomeHero)||void 0===t?void 0:t.call(n)},accountExpenses:function(){var t;return null===(t=n.updateAccountExpensesHero)||void 0===t?void 0:t.call(n)}}[t];if(r)try{r()}catch(e){console.error("Failed to refresh tile",t,e)}}},{key:"aggregateToTopLevel",value:function(t){if(!t||!Array.isArray(t)||0===t.length)return t;var e,n=this.app.categories||[],a={},r={},i=Ot(n);try{for(i.s();!(e=i.n()).done;){var o=e.value;a[o.id]=o}}catch(t){i.e(t)}finally{i.f()}var s,c=function(t){if(void 0!==r[t])return r[t];var e=a[t];return e&&e.parentId?(r[t]=c(e.parentId),r[t]):(r[t]=t,t)},l={},u=Ot(t);try{for(u.s();!(s=u.n()).done;){var d=s.value,h=d.id||d.categoryId,g=c(h),p=a[g];l[g]||(l[g]=Wt(Wt({},d),{},{id:g,categoryId:g,name:(null==p?void 0:p.name)||d.categoryName||d.name,categoryName:(null==p?void 0:p.name)||d.categoryName||d.name,color:(null==p?void 0:p.color)||d.color,total:0,amount:0,count:0,budgeted:0,budget:0,spent:0,carried:0})),l[g].total+=Math.abs(parseFloat(d.total||d.amount||0)),l[g].amount+=Math.abs(parseFloat(d.total||d.amount||0)),l[g].count+=parseInt(d.count||1),l[g].budgeted+=parseFloat(d.budgeted||d.budget||0),l[g].budget+=parseFloat(d.budgeted||d.budget||0),l[g].spent+=parseFloat(d.spent||0),l[g].carried+=parseFloat(d.carried||0)}}catch(t){u.e(t)}finally{u.f()}return Object.values(l)}},{key:"resizeAllCharts",value:function(){var t=this;Object.keys(this.charts||{}).forEach(function(e){var n=t.charts[e];if(n&&"function"==typeof n.resize&&n.canvas&&n.canvas.isConnected)try{n.resize()}catch(t){console.warn("Chart resize failed for ".concat(e,":"),t)}})}},{key:"updateAddTilesMenu",value:function(){var t=this,e=document.getElementById("add-tiles-menu-list");if(e){e.innerHTML="";var n={};if(Object.entries(nt.hero).forEach(function(e){var a=Nt(e,2),r=a[0],i=a[1];if(!t.dashboardConfig.hero.visibility[r]){var o=i.category||"other";n[o]||(n[o]=[]),n[o].push({key:r,name:i.name,type:"hero",size:"hero"})}}),Object.entries(nt.widgets).forEach(function(e){var a=Nt(e,2),r=a[0],i=a[1];if(!t.dashboardConfig.widgets.visibility[r]){var o=i.category||"other";n[o]||(n[o]=[]),n[o].push({key:r,name:i.name,type:"widget",size:i.defaultSize})}}),0!==Object.values(n).reduce(function(t,e){return t+e.length},0)){[{key:"insights",label:(0,i.Tl)("budget","Insights & Analytics")},{key:"budgeting",label:(0,i.Tl)("budget","Budgeting")},{key:"forecasting",label:(0,i.Tl)("budget","Forecasting")},{key:"transactions",label:(0,i.Tl)("budget","Transactions")},{key:"income",label:(0,i.Tl)("budget","Income")},{key:"debts",label:(0,i.Tl)("budget","Debts")},{key:"goals",label:(0,i.Tl)("budget","Goals")},{key:"bills",label:(0,i.Tl)("budget","Bills")},{key:"alerts",label:(0,i.Tl)("budget","Alerts")},{key:"interactive",label:(0,i.Tl)("budget","Interactive")},{key:"other",label:(0,i.Tl)("budget","Other")}].forEach(function(t){var a=t.key,r=t.label,o=n[a];if(o&&0!==o.length){var s=document.createElement("div");s.className="add-tiles-category-header",s.textContent=r,e.appendChild(s),o.forEach(function(t){var n=document.createElement("div");n.className="add-tiles-menu-item";var a="hero"===t.size?''.concat((0,i.Tl)("budget","Hero"),""):"";n.innerHTML='\n \n '.concat(t.name,"\n ").concat(a,'\n \n \n '),e.appendChild(n)})}});var a=[];if(Kt.forEach(function(e){if(!1!==t.dashboardConfig.widgets.visibility[e]&&t.countInstances(e)<5){var n=nt.widgets[e];n&&a.push({key:e,name:n.name})}}),a.length>0){var r=document.createElement("div");r.className="add-tiles-category-header",r.textContent=(0,i.Tl)("budget","Add Another"),e.appendChild(r),a.forEach(function(n){var a=document.createElement("div");a.className="add-tiles-menu-item",a.innerHTML='\n \n '.concat(n.name,'\n ').concat(t.countInstances(n.key),"/").concat(5,'\n \n \n '),e.appendChild(a)})}e.querySelectorAll(".add-tile-btn:not(.add-another-btn)").forEach(function(e){e.addEventListener("click",function(n){n.stopPropagation();var a=e.dataset.widgetId,r=e.dataset.category;t.showWidget(a,r)})}),e.querySelectorAll(".add-another-btn").forEach(function(e){e.addEventListener("click",function(n){n.stopPropagation(),t.addWidgetInstance(e.dataset.widgetType)})})}else e.innerHTML='
'.concat((0,i.Tl)("budget","All tiles are visible"),"
")}}},{key:"createSavedInstances",value:function(){var t,e=(null===(t=this.dashboardConfig.widgets)||void 0===t?void 0:t.instances)||{},n=document.querySelector(".dashboard-grid");if(n)for(var a=0,r=Object.entries(e);a=5)){t.n=2;break}return(0,c.Qg)((0,i.Tl)("budget","Maximum of {max} instances reached",{max:5})),t.a(2);case 2:if(a=this.generateInstanceId(e),this.dashboardConfig.widgets.instances||(this.dashboardConfig.widgets.instances={}),this.dashboardConfig.widgets.instances[a]=e,this.dashboardConfig.widgets.visibility[a]=!0,r=(null===(n=nt.widgets[e])||void 0===n?void 0:n.defaultSize)||"m",this.dashboardConfig.widgets.sizes||(this.dashboardConfig.widgets.sizes={}),this.dashboardConfig.widgets.sizes[a]=r,this.dashboardConfig.widgets.order||(this.dashboardConfig.widgets.order=[]),this.dashboardConfig.widgets.order.push(a),o=this.createWidgetDOM(a)){t.n=3;break}return t.a(2);case 3:if(s=document.querySelector(".dashboard-grid")){t.n=4;break}return t.a(2);case 4:return this.gridstack?(l=$t[r]||{w:2,h:4},u="l"===r?this.gridColumns||3:l.w,(d=document.createElement("div")).className="grid-stack-item",d.setAttribute("gs-id",a),d.setAttribute("gs-w",u),d.setAttribute("gs-h",l.h),d.setAttribute("gs-auto-position","true"),(h=document.createElement("div")).className="grid-stack-item-content",h.appendChild(o),d.appendChild(h),s.appendChild(d),this.gridstack.makeWidget(d)):s.appendChild(o),this._saveGridstackPositions(),this.saveDashboardVisibility("widgets"),this.dashboardLocked||this.addTileControls(),t.n=5,this.refreshWidgetInstance(a);case 5:this.updateTilePeriodIndicators(),this.updateTileAccountIndicators(),this.updateAddTilesMenu(),(0,c.Te)((0,i.Tl)("budget","Tile added"));case 6:return t.a(2)}},t,this)})),function(e){return t.apply(this,arguments)})},{key:"removeWidgetInstance",value:function(t){var e,n,a,r,o,s;if(this.isDuplicateInstance(t)){if(this.gridstack){var l=document.querySelector('.grid-stack-item[gs-id="'.concat(t,'"]'));l&&this.gridstack.removeWidget(l)}else{var u=this.getWidgetCard(t);u&&u.remove()}this.charts[t]&&(this.charts[t].destroy(),delete this.charts[t]),null===(e=this.dashboardConfig.widgets.instances)||void 0===e||delete e[t],null===(n=this.dashboardConfig.widgets.visibility)||void 0===n||delete n[t],null===(a=this.dashboardConfig.widgets.sizes)||void 0===a||delete a[t],null===(r=this.dashboardConfig.widgets.positions)||void 0===r||delete r[t],null===(o=this.dashboardConfig.widgets.tileSettings)||void 0===o||delete o[t];var d=null===(s=this.dashboardConfig.widgets.order)||void 0===s?void 0:s.indexOf(t);d>-1&&this.dashboardConfig.widgets.order.splice(d,1),this.saveDashboardVisibility("widgets"),this.updateAddTilesMenu(),(0,c.Te)((0,i.Tl)("budget","Tile removed"))}else this.hideWidget(t,"widgets")}}]);var t,e,n,a,l,u,d,h,p,f,m,v,y,b,w,k,E,x,S,C,I,A,_,M,D,B,L,P,O}(),ee=n(933),ne=n(475),ae=n(400),re=n(707);function ie(t,e){return(t||[]).filter(function(t){return!t._shared&&null!=t.accountId&&Number(t.accountId)===Number(null==e?void 0:e.accountId)})}function oe(t){return"one-time"===t.frequency?t.startDate||t.nextDueDate||null:!1===t.isActive?null:t.nextDueDate||null}function se(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;return new Promise(function(a){var r=document.getElementById("bill-link-modal");r&&r.remove();var c=(t||[]).map(function(t){return{bill:t,due:oe(t),exact:null!=n&&(e=t.amount,a=n.amount,r=(0,ae.F)(e),i=(0,ae.F)(a),Number.isFinite(r)&&Number.isFinite(i)&&Math.abs(r)===Math.abs(i))};var e,a,r,i}),l=function(t){return t.due||t.bill.lastPaidDate||"9999-12-31"};c.sort(function(t,e){var n,a;return Number(e.exact)-Number(t.exact)||String(null!==(n=t.bill.name)&&void 0!==n?n:"").localeCompare(String(null!==(a=e.bill.name)&&void 0!==a?a:""))||l(t).localeCompare(l(e))||Number(t.bill.id)-Number(e.bill.id)});var u=c.map(function(t){var n=t.bill,a=t.due,r=t.exact,c=n.currency||(null==e?void 0:e.default_currency)||"",l=[a?(0,i.Tl)("budget","Due {date}",{date:o.Yq(a,e)}):null,n.lastPaidDate?(0,i.Tl)("budget","Paid {date}",{date:o.Yq(n.lastPaidDate,e)}):null,!1===n.isActive?(0,i.Tl)("budget","Inactive"):null].filter(Boolean).join(" · ");return'\n \n ")}).join(""),d=c.length>0?'

'.concat((0,i.Tl)("budget","Choose the bill this transaction paid. It then counts as one of the bill's payments, in the Bills Calendar too. The bill's due date doesn't change."),'

\n
').concat(u,"
"):'

'.concat((0,i.Tl)("budget","There are no bills on this account yet. Add the bill first, then link this payment to it."),"

"),h=document.createElement("div");h.id="bill-link-modal",h.className="budget-modal-overlay",h.innerHTML='\n \n "),document.body.appendChild(h);var g=Date.now();(0,re.oZ)(h,".matching-tx-option",g),(0,re.ou)(h,g);var p=function(t){document.removeEventListener("keydown",f,!0),h.remove(),a(t)},f=function(t){"Escape"===t.key&&document.body.contains(h)&&(t.preventDefault(),t.stopPropagation(),p(null))};document.addEventListener("keydown",f,!0),h.querySelector(".close-btn").addEventListener("click",function(){return p(null)}),h.querySelector(".cancel-btn").addEventListener("click",function(){return p(null)}),h.addEventListener("click",function(t){t.target!==h||(0,re.rV)(t,g)||p(null)});var m=h.querySelector(".confirm-btn");m&&(h.addEventListener("change",function(t){"bill-link-choice"===t.target.name&&(m.disabled=!1)}),m.addEventListener("click",function(){var t=h.querySelector('input[name="bill-link-choice"]:checked');t&&p(parseInt(t.value,10))})),(h.querySelector('input[name="bill-link-choice"]')||h.querySelector(".cancel-btn")).focus()})}function ce(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,a=Array(e);ni&&o>i;t.classList.toggle("cell-popup--above",s),t.style.top="".concat(s?Math.max(8,n.top-a):n.bottom,"px"),t.style.left="".concat(Math.max(8,Math.min(n.left,window.innerWidth-8-r)),"px")}function ue(t,e){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).onHidden,a=void 0===n?null:n;t.classList.add("cell-popup");var r=!1,i=function(){return!t.isConnected||r?(window.removeEventListener("scroll",i,!0),void window.removeEventListener("resize",i)):a&&function(t){var e=t.closest(".table-scroll");if(!e)return!1;var n=e.getBoundingClientRect();if(!n.height||!n.width)return!1;var a=n.top,r=function(t){return function(t){if(Array.isArray(t))return ce(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return ce(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?ce(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}(e.querySelectorAll("thead th")).find(function(t){return t.getBoundingClientRect().height>0});if(r){var i=r.getBoundingClientRect();i.top>=n.top-1&&i.bottom>a&&(a=i.bottom)}var o=t.getBoundingClientRect();return o.bottom<=a||o.top>=n.bottom||o.right<=n.left||o.left>=n.right}(e)?(r=!0,t.style.display="none",void a()):void("none"!==t.style.display&&le(t,e))};return window.addEventListener("scroll",i,!0),window.addEventListener("resize",i),function(){return le(t,e)}}function de(t,e,n){return{name:t,groupName:n,priority:1,active:!0,applyOnImport:!1,schemaVersion:2,criteria:{version:2,root:{operator:"AND",conditions:[{type:"condition",field:"description",matchType:"equals",pattern:t}]}},actions:{version:2,stopProcessing:!0,actions:[{type:"set_category",value:Number(e)}]},stopProcessing:!0}}function he(t,e){var n=String(e).toLowerCase();return(t||[]).find(function(t){var e,a;if(2!==t.schemaVersion||!1!==t.applyOnImport)return!1;var r=null===(e=t.criteria)||void 0===e||null===(e=e.root)||void 0===e?void 0:e.conditions;if(!Array.isArray(r)||1!==r.length)return!1;var i=r[0];return"description"===i.field&&"equals"===i.matchType&&String(null!==(a=i.pattern)&&void 0!==a?a:"").toLowerCase()===n})||null}var ge=n(421),pe=n(328);function fe(t){return fe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},fe(t)}function me(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=Ie(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var a=0,r=function(){};return{s:r,n:function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,o=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return o=t.done,t},e:function(t){s=!0,i=t},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw i}}}}function ve(t){return function(t){if(Array.isArray(t))return Ae(t)}(t)||_e(t)||Ie(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ye(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,a)}return n}function be(t){for(var e=1;e3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(ke(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,ke(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,ke(d,"constructor",l),ke(l,"constructor",c),c.displayName="GeneratorFunction",ke(l,r,"GeneratorFunction"),ke(d),ke(d,r,"Generator"),ke(d,a,function(){return this}),ke(d,"toString",function(){return"[object Generator]"}),(Te=function(){return{w:i,m:h}})()}function ke(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}ke=function(t,e,n,a){function i(e,n){ke(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},ke(t,e,n,a)}function Ee(t,e){return Me(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var a,r,i,o,s=[],c=!0,l=!1;try{if(i=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(a=i.call(n)).done)&&(s.push(a.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw r}}return s}}(t,e)||Ie(t,e)||Ce()}function xe(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function Se(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){xe(i,a,r,o,s,"next",t)}function s(t){xe(i,a,r,o,s,"throw",t)}o(void 0)})}}function Ce(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ie(t,e){if(t){if("string"==typeof t)return Ae(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Ae(t,e):void 0}}function Ae(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,a=Array(e);n1&&(t.app.currentPage--,t.app.loadTransactions())});var k=document.getElementById("next-page-btn");k&&k.addEventListener("click",function(){t.app.currentPage++,t.app.loadTransactions()});var E=document.getElementById("prev-page-btn-bottom");E&&E.addEventListener("click",function(){t.app.currentPage>1&&(t.app.currentPage--,t.app.loadTransactions())});var x=document.getElementById("next-page-btn-bottom");x&&x.addEventListener("click",function(){t.app.currentPage++,t.app.loadTransactions()}),document.addEventListener("click",function(e){var n=e.target.closest("#transactions-table th.sortable");n&&t.sortTransactions(n.getAttribute("data-sort")),"select-all-transactions"===e.target.id&&t.toggleAllTransactionSelection(e.target.checked),e.target.classList.contains("transaction-checkbox")&&t.handleTransactionCheckbox(e.target)})}},{key:"handleTransactionCheckbox",value:function(t){var e=parseInt(t.getAttribute("data-transaction-id")),n=this.reconcileMode&&this.reconcileSession;if(n&&t.checked&&!this.isReconcileTickable(e))return t.checked=!1,void(0,c.I9)((0,i.Tl)("budget","This transaction is scheduled, so it is not on a statement yet and cannot be ticked."));this.toggleTransactionSelection(e,t.checked),n&&this.queueReconcileTick(e,t.checked)}},{key:"isReconcileTickable",value:function(t){var e,n,a=null===(e=this.app.transactions)||void 0===e?void 0:e.find(function(e){return e.id===t});return"scheduled"!==(null!==(n=null==a?void 0:a.status)&&void 0!==n?n:"cleared")}},{key:"toggleFiltersPanel",value:function(){var t=document.getElementById("transactions-filters"),e=document.getElementById("toggle-filters-btn");"none"===t.style.display?(t.style.display="block",e.classList.add("active"),this.populateFilterDropdowns()):(t.style.display="none",e.classList.remove("active"))}},{key:"refreshFilterTags",value:function(){var t=this,e=document.getElementById("transactions-filters");e&&"none"!==e.style.display&&this.loadFilterTags().then(function(){return t.populateFilterTagsDropdown()})}},{key:"syncFilterControlsFromState",value:function(){var t=this.app.transactionFilters||{};this.selectedFilterTags=new Set(t.tagIds||[]);var e=document.getElementById("transactions-filters");if(e&&"none"!==e.style.display){var n=function(t,e){var n=document.getElementById(t);n&&(n._flatpickr?e?n._flatpickr.setDate(e,!1):n._flatpickr.clear(!1):n.value=e||"")};n("filter-account",t.account),this.syncCategoryFilterControl(t.category),n("filter-type",t.type),n("filter-status",t.status),n("filter-reconciled",t.reconciled),n("filter-date-from",t.dateFrom),n("filter-date-to",t.dateTo),n("filter-created-from",t.createdAtFrom),n("filter-created-to",t.createdAtTo),n("filter-amount-min",t.amountMin),n("filter-amount-max",t.amountMax),n("filter-search",t.search)}}},{key:"syncCategoryFilterControl",value:function(t){var e=document.getElementById("filter-category");if(e){var n=e.querySelector("option[data-synthetic-category]");n&&n.remove();var a=t?String(t).split(","):[];if(a.length<=1)e.value=t||"";else{var r=function(t){return Me(t)||_e(t)||Ie(t)||Ce()}(a),o=r[0],s=r.slice(1),c=(this.app.categories||[]).find(function(t){return String(t.id)===String(o)}),l=c?c.name:o,u=document.createElement("option");u.value=String(t),u.dataset.syntheticCategory="true",u.textContent=(0,i.zw)("budget","{category} + {count} subcategory","{category} + {count} subcategories",s.length,{category:l,count:s.length});var d=Array.from(e.options).find(function(t){return t.value===String(o)});d?d.after(u):e.insertBefore(u,e.firstChild),e.value=String(t)}}}},{key:"populateFilterDropdowns",value:function(){var t=this,e=document.getElementById("filter-account");e&&this.accounts&&(e.innerHTML='")+this.accounts.map(function(t){return'")}).join(""));var n=document.getElementById("filter-category");n&&this.categories&&(n.innerHTML='"),s.Vb(n,this.categoryTree||this.categories)),this.syncFilterControlsFromState();var a=document.getElementById("reconcile-account");a&&this.accounts&&(a.innerHTML='"),(0,k.HB)(this.accounts).forEach(function(t){a.innerHTML+='")})),this.loadFilterTags().then(function(){return t.populateFilterTagsDropdown()})}},{key:"loadFilterTags",value:(pt=Se(Te().m(function t(){var e,n,a,r,o;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,Promise.all([(0,T.n)("/apps/budget/api/tag-sets").catch(function(){return null}),(0,T.n)("/apps/budget/api/tags/global").catch(function(){return null})]);case 1:e=t.v,n=Ee(e,2),a=n[0],r=n[1],a&&(this.allFilterTagSets=a),r&&r.length>0&&(this.allFilterTagSets=this.allFilterTagSets||[],this.allFilterTagSets.unshift({id:"global",name:(0,i.Tl)("budget","Tags"),tags:r})),t.n=3;break;case 2:t.p=2,o=t.v,console.error("Failed to load tags for filter:",o);case 3:return t.a(2)}},t,this,[[0,2]])})),function(){return pt.apply(this,arguments)})},{key:"populateFilterTagsDropdown",value:function(){var t=this,e=document.getElementById("filter-tags");if(e)if(e.innerHTML="",this.allFilterTagSets&&0!==this.allFilterTagSets.length){var n=document.createElement("div");n.className="filter-tags-chips";var a=document.createElement("input");a.type="text",a.id="filter-tags-input",a.className="tags-autocomplete-input",a.placeholder=(0,i.Tl)("budget","Type to filter tags...");var r=document.createElement("div");r.className="tags-autocomplete-dropdown",r.style.display="none",e.appendChild(n),e.appendChild(a),e.appendChild(r);var o=function(){n.innerHTML="",0!==t.selectedFilterTags.size?(n.style.display="flex",t.selectedFilterTags.forEach(function(e){var r=c.find(function(t){return t.id===e});if(r){var i=document.createElement("span");i.className="filter-tag-chip",i.style.cssText="display: inline-flex; align-items: center; gap: 4px; background-color: ".concat(s.ZD(r.color||"#888"),"; color: white; padding: 2px 8px; border-radius: 10px; font-size: 11px; cursor: pointer;"),i.innerHTML="".concat(s.ZD(r.name),' ×'),i.addEventListener("click",function(){t.selectedFilterTags.delete(e),o(),l(a.value),t.updateFilters()}),n.appendChild(i)}})):n.style.display="none"},c=[];this.allFilterTagSets.forEach(function(t){t.tags&&t.tags.length>0&&t.tags.forEach(function(e){c.push({id:e.id,name:e.name,color:e.color,tagSetName:t.name,tagSetId:t.id})})});var l=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=e?c.filter(function(t){return t.name.toLowerCase().includes(e.toLowerCase())||t.tagSetName.toLowerCase().includes(e.toLowerCase())}):c,a={};n.forEach(function(t){a[t.tagSetId]||(a[t.tagSetId]={name:t.tagSetName,tags:[]}),a[t.tagSetId].tags.push(t)});var o="";Object.values(a).forEach(function(e){o+='
'.concat(s.ZD(e.name),"
"),e.tags.forEach(function(e){var n=t.selectedFilterTags.has(e.id);o+='\n
\n \n ').concat(s.ZD(e.name),'\n \n ').concat(n?"✓":"","\n
\n ")})}),r.innerHTML=o||'
'.concat((0,i.Tl)("budget","No tags found"),"
"),r.style.display="block"};a.addEventListener("focus",function(){return l(a.value)}),a.addEventListener("input",function(){return l(a.value)}),r.addEventListener("mousedown",function(e){e.preventDefault(),e.stopPropagation();var n=e.target.closest(".tags-autocomplete-item");if(n){var r=parseInt(n.dataset.tagId),i=c.find(function(t){return t.id===r});if(!i)return;c.filter(function(t){return t.tagSetId===i.tagSetId}).forEach(function(e){e.id!==r&&t.selectedFilterTags.delete(e.id)}),t.selectedFilterTags.has(r)?t.selectedFilterTags.delete(r):t.selectedFilterTags.add(r),o(),l(a.value),t.updateFilters()}}),r.addEventListener("click",function(t){t.stopPropagation()}),o(),document.addEventListener("click",function(t){e.contains(t.target)||(r.style.display="none")})}else e.innerHTML='
'.concat((0,i.Tl)("budget","No tags available"),"
")}},{key:"_maybeCheckReconcileSession",value:function(t){t&&String(t)!==this._lastReconCheckedAccount&&(this._lastReconCheckedAccount=String(t),this.checkActiveReconcileSession(parseInt(t)))}},{key:"resetAllMatchingSelectionOnFilterChange",value:function(){if(this.allMatchingSelection){this.allMatchingSelection=null,this.selectedTransactions.clear();var t=document.getElementById("select-all-transactions");t&&(t.checked=!1,t.indeterminate=!1),this.updateBulkActionsState()}}},{key:"updateFilters",value:function(){var t,e,n,a,r,i,o,s,c,l,u,d;this.resetAllMatchingSelectionOnFilterChange(),this.app.transactionFilters={account:(null===(t=document.getElementById("filter-account"))||void 0===t?void 0:t.value)||"",category:(null===(e=document.getElementById("filter-category"))||void 0===e?void 0:e.value)||"",type:(null===(n=document.getElementById("filter-type"))||void 0===n?void 0:n.value)||"",status:(null===(a=document.getElementById("filter-status"))||void 0===a?void 0:a.value)||"",reconciled:(null===(r=document.getElementById("filter-reconciled"))||void 0===r?void 0:r.value)||"",dateFrom:(null===(i=document.getElementById("filter-date-from"))||void 0===i?void 0:i.value)||"",dateTo:(null===(o=document.getElementById("filter-date-to"))||void 0===o?void 0:o.value)||"",createdAtFrom:(null===(s=document.getElementById("filter-created-from"))||void 0===s?void 0:s.value)||"",createdAtTo:(null===(c=document.getElementById("filter-created-to"))||void 0===c?void 0:c.value)||"",amountMin:(null===(l=document.getElementById("filter-amount-min"))||void 0===l?void 0:l.value)||"",amountMax:(null===(u=document.getElementById("filter-amount-max"))||void 0===u?void 0:u.value)||"",search:(null===(d=document.getElementById("filter-search"))||void 0===d?void 0:d.value)||"",tagIds:Array.from(this.selectedFilterTags)},this.app.currentPage=1,this.app.loadTransactions(),this._maybeCheckReconcileSession(this.app.transactionFilters.account)}},{key:"applySearchLink",value:function(t){this.app.transactionFilters=be(be({},this.app.transactionFilters||{}),{},{search:t}),this.app.currentPage=1;var e=document.getElementById("transactions-filters");"none"===(null==e?void 0:e.style.display)?this.toggleFiltersPanel():this.syncFilterControlsFromState()}},{key:"clearFilters",value:function(){this.resetAllMatchingSelectionOnFilterChange(),this.app.transactionFilters={},this.syncFilterControlsFromState(),this.app.currentPage=1,this.app.loadTransactions()}},{key:"sortTransactions",value:function(t){var e=this;this.app.currentSort.field===t?this.app.currentSort.direction="asc"===this.app.currentSort.direction?"desc":"asc":(this.app.currentSort.field=t,this.app.currentSort.direction="asc"),document.querySelectorAll("#transactions-table .sort-indicator").forEach(function(t){t.className="sort-indicator"});var n=document.querySelector('#transactions-table [data-sort="'.concat(t,'"] .sort-indicator'));n&&(n.className="sort-indicator ".concat(this.app.currentSort.direction)),document.querySelectorAll("#transactions-table th[data-sort]").forEach(function(n){n.setAttribute("aria-sort",n.dataset.sort===t?"asc"===e.app.currentSort.direction?"ascending":"descending":"none")}),this.app.loadTransactions()}},{key:"toggleBulkMode",value:function(){var t=document.getElementById("bulk-actions-panel"),e=document.getElementById("bulk-actions-btn");"none"===t.style.display?(t.style.display="block",e.classList.add("active")):this.cancelBulkMode()}},{key:"cancelBulkMode",value:function(){var t=document.getElementById("bulk-actions-panel"),e=document.getElementById("bulk-actions-btn");t.style.display="none",e.classList.remove("active"),this.selectedTransactions.clear(),this.allMatchingSelection=null,document.querySelectorAll(".transaction-checkbox:checked").forEach(function(t){t.checked=!1});var n=document.getElementById("select-all-transactions");n&&(n.checked=!1,n.indeterminate=!1),this.updateBulkActionsState(),this.refreshSelectAllBanner()}},{key:"toggleAllTransactionSelection",value:function(t){var e=this;if(this.allMatchingSelection=null,this.reconcileMode&&this.reconcileSession)return document.querySelectorAll(".transaction-checkbox").forEach(function(n){var a=parseInt(n.getAttribute("data-transaction-id"));t&&!e.isReconcileTickable(a)||(n.checked!==t&&(n.checked=t,e.queueReconcileTick(a,t)),t?e.selectedTransactions.add(a):e.selectedTransactions.delete(a))}),this.updateBulkActionsState(),void this.refreshSelectAllBanner();this.selectedTransactions.clear(),t?document.querySelectorAll(".transaction-checkbox").forEach(function(t){t.checked=!0;var n=parseInt(t.getAttribute("data-transaction-id"));e.selectedTransactions.add(n)}):document.querySelectorAll(".transaction-checkbox").forEach(function(t){t.checked=!1}),this.updateBulkActionsState(),this.refreshSelectAllBanner()}},{key:"toggleTransactionSelection",value:function(t,e){this.allMatchingSelection=null,e?this.selectedTransactions.add(t):this.selectedTransactions.delete(t);var n=document.getElementById("select-all-transactions"),a=document.querySelectorAll(".transaction-checkbox"),r=document.querySelectorAll(".transaction-checkbox:checked");n&&(n.checked=a.length===r.length&&a.length>0,n.indeterminate=r.length>0&&r.length0&&s>r&&o===r)return e.textContent=(0,i.zw)("budget","All %n transaction on this page is selected.","All %n transactions on this page are selected.",r),n.textContent=(0,i.Tl)("budget","Select all {total} matching transactions",{total:s}),void(t.style.display="flex");t.style.display="none"}}},{key:"updateBulkActionsState",value:function(){var t=this.selectedTransactions.size,e=document.getElementById("selected-count"),n=document.getElementById("bulk-actions-btn"),a=document.getElementById("bulk-delete-btn"),r=document.getElementById("bulk-reconcile-btn"),i=document.getElementById("bulk-unreconcile-btn"),o=document.getElementById("bulk-edit-btn"),s=document.getElementById("bulk-tags-btn");e&&(e.textContent=t);var c=0===t;n&&(n.disabled=c),a&&(a.disabled=c),r&&(r.disabled=c),i&&(i.disabled=c),o&&(o.disabled=c),s&&(s.disabled=c)}},{key:"bulkDeleteTransactions",value:(dt=Se(Te().m(function t(){var e,n,a,r,o,s=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(0!==this.selectedTransactions.size){t.n=1;break}return t.a(2);case 1:return e=this.transactions.filter(function(t){return s.selectedTransactions.has(t.id)}),n=this.allMatchingSelection?this.allMatchingSelection.billCount:e.filter(function(t){return t.billId}).length,a=(0,i.zw)("budget","Are you sure you want to delete %n transaction? This action cannot be undone.","Are you sure you want to delete %n transactions? This action cannot be undone.",this.selectedTransactions.size),n>0&&(a+="\n\n"+(0,i.zw)("budget","%n of these was auto-generated from bill payments. Deleting real payments will cause your balance to diverge from your bank statement.","%n of these were auto-generated from bill payments. Deleting real payments will cause your balance to diverge from your bank statement.",n)),t.n=2,(0,l.ZD)(a,{destructive:!0});case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/transactions/bulk-delete",{method:"POST",body:{ids:Array.from(this.selectedTransactions)}});case 4:(r=t.v).success>0&&((0,c.Te)((0,i.zw)("budget","Successfully deleted %n transaction","Successfully deleted %n transactions",r.success)),this.selectedTransactions.clear(),this.allMatchingSelection=null,this.app.currentPage=1,this.app.loadTransactions()),r.failed>0&&(0,c.Qg)((0,i.zw)("budget","Failed to delete %n transaction","Failed to delete %n transactions",r.failed)),t.n=6;break;case 5:t.p=5,o=t.v,console.error("Bulk deletion failed:",o),(0,c.Qg)((0,i.Tl)("budget","Failed to delete transactions"));case 6:return t.a(2)}},t,this,[[3,5]])})),function(){return dt.apply(this,arguments)})},{key:"bulkReconcileTransactions",value:(ut=Se(Te().m(function t(){var e,n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(0!==this.selectedTransactions.size){t.n=1;break}return t.a(2);case 1:return t.n=2,(0,l.ZD)((0,i.zw)("budget","Are you sure you want to mark %n transaction as reconciled?","Are you sure you want to mark %n transactions as reconciled?",this.selectedTransactions.size));case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/transactions/bulk-reconcile",{method:"POST",body:{ids:Array.from(this.selectedTransactions),reconciled:!0}});case 4:(e=t.v).success>0&&((0,c.Te)((0,i.zw)("budget","Successfully reconciled %n transaction","Successfully reconciled %n transactions",e.success)),this.selectedTransactions.clear(),this.allMatchingSelection=null,this.app.currentPage=1,this.app.loadTransactions()),e.failed>0&&(0,c.Qg)((0,i.zw)("budget","Failed to reconcile %n transaction","Failed to reconcile %n transactions",e.failed)),t.n=6;break;case 5:t.p=5,n=t.v,console.error("Bulk reconcile failed:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to reconcile transactions"));case 6:return t.a(2)}},t,this,[[3,5]])})),function(){return ut.apply(this,arguments)})},{key:"bulkUnreconcileTransactions",value:(lt=Se(Te().m(function t(){var e,n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(0!==this.selectedTransactions.size){t.n=1;break}return t.a(2);case 1:return t.n=2,(0,l.ZD)((0,i.zw)("budget","Are you sure you want to mark %n transaction as unreconciled?","Are you sure you want to mark %n transactions as unreconciled?",this.selectedTransactions.size));case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/transactions/bulk-reconcile",{method:"POST",body:{ids:Array.from(this.selectedTransactions),reconciled:!1}});case 4:(e=t.v).success>0&&((0,c.Te)((0,i.zw)("budget","Successfully unreconciled %n transaction","Successfully unreconciled %n transactions",e.success)),this.selectedTransactions.clear(),this.allMatchingSelection=null,this.app.currentPage=1,this.app.loadTransactions()),e.failed>0&&(0,c.Qg)((0,i.zw)("budget","Failed to unreconcile %n transaction","Failed to unreconcile %n transactions",e.failed)),t.n=6;break;case 5:t.p=5,n=t.v,console.error("Bulk unreconcile failed:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to unreconcile transactions"));case 6:return t.a(2)}},t,this,[[3,5]])})),function(){return lt.apply(this,arguments)})},{key:"showBulkEditModal",value:function(){var t=this;if(0!==this.selectedTransactions.size){var e=document.getElementById("bulk-edit-modal"),n=document.getElementById("bulk-edit-count"),a=document.getElementById("bulk-edit-category");if(n&&(n.textContent=this.selectedTransactions.size),a&&this.categories){a.innerHTML='")+'");var r=(this.transactions||[]).filter(function(e){return t.selectedTransactions.has(e.id)}).map(function(e){return(t.accounts||[]).find(function(t){return t.id===e.accountId})}),o=(0,k.hM)(this.categories,r);s.Vb(a,o?(0,k.QN)(o):this.categoryTree||this.categories)}document.getElementById("bulk-edit-vendor").value="",document.getElementById("bulk-edit-reference").value="",document.getElementById("bulk-edit-notes").value="",e.style.display="flex"}}},{key:"submitBulkEdit",value:(ct=Se(Te().m(function t(){var e,n,a,r,o,s,u;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.getElementById("bulk-edit-category").value,n=document.getElementById("bulk-edit-vendor").value.trim(),a=document.getElementById("bulk-edit-reference").value.trim(),r=document.getElementById("bulk-edit-notes").value.trim(),o={},"none"===e?o.categoryId=null:e&&(o.categoryId=parseInt(e)),n&&(o.vendor=n),a&&(o.reference=a),r&&(o.notes=r),0!==Object.keys(o).length){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please fill in at least one field to update")),t.a(2);case 1:return t.n=2,(0,l.ZD)((0,i.zw)("budget","Are you sure you want to update %n transaction?","Are you sure you want to update %n transactions?",this.selectedTransactions.size));case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/transactions/bulk-edit",{method:"POST",body:{ids:Array.from(this.selectedTransactions),updates:o}});case 4:(s=t.v).success>0&&((0,c.Te)((0,i.zw)("budget","Successfully updated %n transaction","Successfully updated %n transactions",s.success)),this.selectedTransactions.clear(),this.allMatchingSelection=null,this.app.currentPage=1,this.app.loadTransactions(),document.getElementById("bulk-edit-modal").style.display="none"),s.failed>0&&(0,c.Qg)((0,i.zw)("budget","Failed to update %n transaction","Failed to update %n transactions",s.failed)),t.n=6;break;case 5:t.p=5,u=t.v,console.error("Bulk edit failed:",u),(0,c.Qg)((0,i.Tl)("budget","Failed to update transactions"));case 6:return t.a(2)}},t,this,[[3,5]])})),function(){return ct.apply(this,arguments)})},{key:"showBulkTagsModal",value:(st=Se(Te().m(function t(){var e,n,a,r,o,c,l,u,d,h,g,p,f,m,v,y=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(0!==this.selectedTransactions.size){t.n=1;break}return t.a(2);case 1:if(e=document.getElementById("bulk-tags-modal"),n=document.getElementById("bulk-tags-description"),a=document.getElementById("bulk-tags-add"),r=document.getElementById("bulk-tags-remove"),o=document.getElementById("bulk-tags-unaffected"),e&&a&&r){t.n=2;break}return t.a(2);case 2:return n&&(n.textContent=(0,i.zw)("budget","Add or remove tags on %n selected transaction. Tags you leave unchecked are not touched.","Add or remove tags on %n selected transactions. Tags you leave unchecked are not touched.",this.selectedTransactions.size)),c=''.concat((0,i.Tl)("budget","Loading..."),""),a.innerHTML=c,r.innerHTML=c,o&&(o.textContent=""),e.style.display="flex",l={totalSelected:0,globalTags:[],tagSets:[],unaffectedCount:0},t.p=3,t.n=4,(0,T.n)("/apps/budget/api/transactions/bulk-tag-options",{method:"POST",body:{ids:Array.from(this.selectedTransactions)}}).catch(function(){return null});case 4:(u=t.v)&&(l=u),t.n=6;break;case 5:t.p=5,v=t.v,console.error("Failed to load bulk tag options:",v);case 6:if(d=(0,ne.g)(l.globalTags||[]),h=(l.tagSets||[]).map(function(t){return be(be({},t),{},{tags:(0,ne.g)(t.tags||[])})}).filter(function(t){return t.tags.length>0}),this._bulkTagNames=new Map,[d].concat(ve(h.map(function(t){return t.tags}))).forEach(function(t){t.forEach(function(t){return y._bulkTagNames.set(t.id,t.name)})}),0!==d.length||0!==h.length){t.n=7;break}return g=''.concat((0,i.Tl)("budget","No tags available"),""),a.innerHTML=g,r.innerHTML=g,t.a(2);case 7:p=function(t,e,n,a){return'\n
\n \n
\n ').concat(n.map(function(t){return'\n \n ")}).join(""),"\n
\n
\n ")},f=function(t){var e="";return d.length>0&&(e+=p((0,i.Tl)("budget","Tags"),"",d,t)),h.forEach(function(n){var a="".concat(n.categoryName," → ").concat(n.name),r=(0,i.Tl)("budget","applies to {count} of {total}",{count:n.matchingCount,total:l.totalSelected});e+=p(a,r,n.tags,t)}),e},a.innerHTML=f("bulk-tag-add"),r.innerHTML=f("bulk-tag-remove"),o&&(o.textContent=l.unaffectedCount>0?(0,i.zw)("budget","%n selected transaction is in a category these tags do not cover.","%n selected transactions are in categories these tags do not cover.",l.unaffectedCount):""),(m=function(t,e){t.querySelectorAll('input[type="checkbox"]').forEach(function(t){t.addEventListener("change",function(){if(t.checked){var n=e.querySelector('input[value="'.concat(t.value,'"]'));n&&(n.checked=!1)}})})})(a,r),m(r,a);case 8:return t.a(2)}},t,this,[[3,5]])})),function(){return st.apply(this,arguments)})},{key:"submitBulkTags",value:(ot=Se(Te().m(function t(){var e,n,a,r,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=(e=function(t){return Array.from(document.querySelectorAll("#".concat(t,' input[type="checkbox"]:checked'))).map(function(t){return parseInt(t.value)})})("bulk-tags-add"),a=e("bulk-tags-remove"),0!==n.length||0!==a.length){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please select at least one tag to add or remove")),t.a(2);case 1:return t.p=1,t.p=2,t.n=3,(0,T.n)("/apps/budget/api/transactions/bulk-tags",{method:"POST",body:{ids:Array.from(this.selectedTransactions),addTagIds:n,removeTagIds:a},errorMessage:(0,i.Tl)("budget","Failed to update tags")});case 3:r=t.v,t.n=6;break;case 4:if(t.p=4,(o=t.v)instanceof T.h){t.n=5;break}throw o;case 5:return(0,c.Qg)(o.message),t.a(2);case 6:r.success>0&&((0,c.Te)(this.bulkTagSummary(r)),this.selectedTransactions.clear(),this.allMatchingSelection=null,this.app.currentPage=1,this.app.loadTransactions(),document.getElementById("bulk-tags-modal").style.display="none"),r.failed>0&&(0,c.Qg)((0,i.zw)("budget","Failed to update tags on %n transaction","Failed to update tags on %n transactions",r.failed)),t.n=8;break;case 7:t.p=7,s=t.v,console.error("Bulk tag update failed:",s),(0,c.Qg)((0,i.Tl)("budget","Failed to update tags"));case 8:return t.a(2)}},t,this,[[2,4],[1,7]])})),function(){return ot.apply(this,arguments)})},{key:"bulkTagSummary",value:function(t){var e=(0,i.zw)("budget","Updated tags on %n transaction","Updated tags on %n transactions",t.success),n=this._bulkTagNames||new Map,a=Object.entries(t.applied||{}).filter(function(e){var a=Ee(e,2),r=a[0];return a[1]0?"".concat(e,". ").concat(a.join(" ")):e}},{key:"toggleReconcileMode",value:function(){var t=document.getElementById("reconcile-panel"),e=document.getElementById("reconcile-mode-btn");"none"===t.style.display?(t.style.display="block",e.classList.add("active"),this.populateFilterDropdowns()):(t.style.display="none",e.classList.remove("active"),this.reconcileMode=!1,this.app.loadTransactions())}},{key:"reconcileErrorMessage",value:function(t){return t instanceof T.h&&null===t.data?(0,i.Tl)("budget","Server error ({status}) — check the Nextcloud logs",{status:t.status}):t.message}},{key:"startReconciliation",value:(it=Se(Te().m(function t(){var e,n,a,r,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.getElementById("reconcile-account").value,n=document.getElementById("reconcile-statement-balance").value,a=document.getElementById("reconcile-statement-date").value,e&&n&&a){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please fill in all reconciliation fields")),t.a(2);case 1:return t.p=1,t.p=2,t.n=3,(0,T.n)("/apps/budget/api/accounts/".concat(e,"/reconciliation/session"),{method:"POST",body:{statementBalance:parseFloat(n),statementDate:a},errorMessage:(0,i.Tl)("budget","Failed to start reconciliation")});case 3:r=t.v,t.n=8;break;case 4:if(t.p=4,(o=t.v)instanceof T.h&&409===o.status){t.n=5;break}throw o;case 5:return t.n=6,(0,l.ZD)((0,i.Tl)("budget","A reconciliation is already in progress for this account. Resume it?"));case 6:if(!t.v){t.n=7;break}return t.n=7,this.enterReconcileSession(o.data.existing);case 7:return t.a(2);case 8:return t.n=9,this.enterReconcileSession(r);case 9:t.n=11;break;case 10:t.p=10,s=t.v,console.error("Reconciliation failed:",s),(0,c.Qg)((0,i.Tl)("budget","Failed to start reconciliation: {message}",{message:this.reconcileErrorMessage(s)}));case 11:return t.a(2)}},t,this,[[2,4],[1,10]])})),function(){return it.apply(this,arguments)})},{key:"enterReconcileSession",value:(rt=Se(Te().m(function t(e){var n,a,r;return Te().w(function(t){for(;;)switch(t.n){case 0:this.reconcileMode=!0,this.reconcileSession=e,this._reconTickQueue=new Set,this._reconUntickQueue=new Set,this.allMatchingSelection=null,this.selectedTransactions=new Set(e.tickedIds||[]),(n=document.getElementById("filter-account"))&&(a=String(e.session.accountId),ve(n.options).some(function(t){return t.value===a})||this.populateFilterDropdowns(),n.value=a,(0,u.Mv)("filter-date-to",e.session.statementDate||""),(r=document.getElementById("filter-reconciled"))&&(r.value="no"),this.updateFilters()),document.getElementById("reconcile-panel").style.display="none",this.renderReconcileBar(),(0,c.Te)((0,i.Tl)("budget","Reconciliation started — tick the transactions on your statement"));case 1:return t.a(2)}},t,this)})),function(t){return rt.apply(this,arguments)})},{key:"renderReconcileBar",value:function(){var t,e,n=this,a=this.reconcileSession;if(a){var r=document.getElementById("reconcile-session-bar");r&&r.remove();var o=document.createElement("div");o.id="reconcile-session-bar",o.className="reconcile-session-bar";var s=a.difference||0,c=a.isBalanced,l=s>0?"credit":"debit",u=a.untickedCount||0;o.innerHTML='\n
\n
\n \n ").concat(this.formatCurrency(a.session.statementBalance),'\n
\n
\n \n ').concat(this.formatCurrency(a.session.startingBalance),'\n
\n
\n \n ").concat(this.formatCurrency(a.tickedSum||0),'\n
\n
\n \n ').concat(this.formatCurrency(s),'\n
\n
\n
\n \n ").concat(u>0?'"):"","\n ").concat(!c&&(a.tickedCount||0)>0?'"):"",'\n \n \n
\n "),document.body.appendChild(o),document.getElementById("finish-reconcile-btn").addEventListener("click",function(){return n.finishReconciliation()}),null===(t=document.getElementById("adjust-reconcile-btn"))||void 0===t||t.addEventListener("click",function(){return n.createReconciliationAdjustment(l,Math.abs(s))}),null===(e=document.getElementById("tick-all-reconcile-btn"))||void 0===e||e.addEventListener("click",function(){return n.tickAllUpToStatementDate()}),document.getElementById("leave-reconcile-btn").addEventListener("click",function(){return n.exitReconcileMode()}),document.getElementById("cancel-reconcile-session-btn").addEventListener("click",function(){return n.cancelReconcileSession()})}}},{key:"tickAllUpToStatementDate",value:(at=Se(Te().m(function t(){var e,n,a;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(this.reconcileSession){t.n=1;break}return t.a(2);case 1:return e=this.reconcileSession.session.accountId,t.p=2,t.n=3,(0,T.n)("/apps/budget/api/accounts/".concat(e,"/reconciliation/tick-all"),{method:"POST",errorMessage:(0,i.Tl)("budget","Failed to tick transactions")});case 3:return n=t.v,this.reconcileSession=n,this.selectedTransactions=new Set(n.tickedIds||[]),this._reconTickQueue.clear(),this._reconUntickQueue.clear(),this.renderReconcileBar(),t.n=4,this.app.loadTransactions();case 4:t.n=6;break;case 5:t.p=5,a=t.v,console.error("Tick all failed:",a),(0,c.Qg)((0,i.Tl)("budget","Failed to tick transactions: {message}",{message:this.reconcileErrorMessage(a)}));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return at.apply(this,arguments)})},{key:"queueReconcileTick",value:function(t,e){var n,a=this;if(this.reconcileSession){e?(this._reconUntickQueue.delete(t),this._reconTickQueue.add(t)):(this._reconTickQueue.delete(t),this._reconUntickQueue.add(t));var r=null===(n=this.app.transactions)||void 0===n?void 0:n.find(function(e){return e.id===t});if(r){var i=("credit"===r.type?1:-1)*parseFloat(r.amount)*(e?1:-1);this.reconcileSession.tickedSum=(this.reconcileSession.tickedSum||0)+i,this.reconcileSession.tickedCount=(this.reconcileSession.tickedCount||0)+(e?1:-1),this.reconcileSession.difference=this.reconcileSession.session.statementBalance-(this.reconcileSession.session.startingBalance+this.reconcileSession.tickedSum),this.reconcileSession.isBalanced=Math.abs(this.reconcileSession.difference)<.005,this.renderReconcileBar()}clearTimeout(this._reconFlushTimer),this._reconFlushTimer=setTimeout(function(){return a.flushReconcileTicks()},400)}}},{key:"flushReconcileTicks",value:(nt=Se(Te().m(function t(){var e,n,a,r,o,s,l,u,d,h;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(this.reconcileSession){t.n=1;break}return t.a(2);case 1:if(e=this.reconcileSession.session.accountId,n=Array.from(this._reconTickQueue),a=Array.from(this._reconUntickQueue),this._reconTickQueue.clear(),this._reconUntickQueue.clear(),0!==n.length||0!==a.length){t.n=2;break}return t.a(2);case 2:t.p=2,r=null,o=0,s=[[n,!0],[a,!1]];case 3:if(!(o".concat((0,i.Tl)("budget","A reconciliation is in progress for this account (statement of {date})",{date:this.formatDate(t.session.statementDate)}),'\n \n \n ");var r=document.querySelector("#transactions-view .table-container");r&&(r.parentNode.insertBefore(a,r),document.getElementById("resume-reconcile-btn").addEventListener("click",Se(Te().m(function n(){return Te().w(function(n){for(;;)switch(n.n){case 0:return a.remove(),n.n=1,e.enterReconcileSession(t);case 1:return n.a(2)}},n)}))),document.getElementById("dismiss-resume-banner-btn").addEventListener("click",function(){return a.remove()}))}},{key:"exitReconcileMode",value:function(){var t,e;this.reconcileMode=!1,this.reconcileSession=null,this.selectedTransactions=new Set,clearTimeout(this._reconFlushTimer),null===(t=document.getElementById("reconcile-session-bar"))||void 0===t||t.remove(),document.getElementById("reconcile-panel").style.display="none",null===(e=document.getElementById("reconcile-mode-btn"))||void 0===e||e.classList.remove("active");var n=document.getElementById("filter-date-to"),a=document.getElementById("filter-reconciled");if(n||a)return(0,u.Mv)("filter-date-to",""),a&&(a.value=""),void this.updateFilters();this.app.loadTransactions()}},{key:"cancelReconcileSession",value:(J=Se(Te().m(function t(){var e,n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(this.reconcileSession){t.n=1;break}return t.a(2);case 1:return t.n=2,(0,l.ZD)((0,i.Tl)("budget","Cancel this reconciliation? Ticked transactions will be released (nothing is marked reconciled)."));case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return e=this.reconcileSession.session.accountId,t.p=4,t.n=5,this.flushReconcileTicks();case 5:return t.n=6,(0,T.n)("/apps/budget/api/accounts/".concat(e,"/reconciliation/session"),{method:"DELETE",errorMessage:(0,i.Tl)("budget","Failed to cancel")});case 6:this.exitReconcileMode(),(0,c.Te)((0,i.Tl)("budget","Reconciliation cancelled")),t.n=8;break;case 7:t.p=7,n=t.v,(0,c.Qg)((0,i.Tl)("budget","Failed to cancel reconciliation: {message}",{message:this.reconcileErrorMessage(n)}));case 8:return t.a(2)}},t,this,[[4,7]])})),function(){return J.apply(this,arguments)})},{key:"cancelReconciliation",value:function(){this.exitReconcileMode()}},{key:"finishReconciliation",value:(X=Se(Te().m(function t(){var e,n,a;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(this.reconcileSession){t.n=1;break}return t.a(2);case 1:return e=this.reconcileSession.session.accountId,t.p=2,t.n=3,this.flushReconcileTicks();case 3:return t.n=4,(0,T.n)("/apps/budget/api/accounts/".concat(e,"/reconciliation/complete"),{method:"POST",errorMessage:(0,i.Tl)("budget","Failed to complete reconciliation")});case 4:n=t.v,this.exitReconcileMode(),this.app.loadAccounts(),this.app.loadTransactions(),(0,c.Te)((0,i.Tl)("budget","Reconciliation completed — {count} transactions marked as reconciled",{count:n.reconciledCount})),n.untickedBeforeStatementDate>0&&(0,c.I9)((0,i.zw)("budget","%n older uncleared transaction was not ticked and remains unreconciled","%n older uncleared transactions were not ticked and remain unreconciled",n.untickedBeforeStatementDate)),t.n=6;break;case 5:t.p=5,a=t.v,(0,c.Qg)((0,i.Tl)("budget","Failed to complete reconciliation: {error}",{error:this.reconcileErrorMessage(a)}));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return X.apply(this,arguments)})},{key:"createReconciliationAdjustment",value:(K=Se(Te().m(function t(e,n){var a,r,s,l,u;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(this.reconcileSession){t.n=1;break}return t.a(2);case 1:return a=this.reconcileSession.session.accountId,r=o.rT(),t.p=2,t.n=3,(0,T.n)("/apps/budget/api/transactions",{method:"POST",body:{date:r,accountId:a,type:e,amount:n,description:(0,i.Tl)("budget","Reconciliation Adjustment"),notes:(0,i.Tl)("budget","Adjustment to match statement balance of {amount}",{amount:this.formatCurrency(this.reconcileSession.session.statementBalance)})},errorMessage:(0,i.Tl)("budget","Failed to create adjustment")});case 3:return s=t.v,t.n=4,(0,T.n)("/apps/budget/api/accounts/".concat(a,"/reconciliation/tick"),{method:"POST",body:{transactionIds:[s.id],ticked:!0}}).catch(function(){return null});case 4:return(l=t.v)&&(this.reconcileSession=l,this.selectedTransactions=new Set(this.reconcileSession.tickedIds||[])),(0,c.Te)((0,i.Tl)("budget","Adjustment transaction created")),t.n=5,this.app.loadTransactions();case 5:this.renderReconcileBar(),t.n=7;break;case 6:t.p=6,u=t.v,console.error("Failed to create adjustment:",u),(0,c.Qg)((0,i.Tl)("budget","Failed to create adjustment: {message}",{message:this.reconcileErrorMessage(u)}));case 7:return t.a(2)}},t,this,[[2,6]])})),function(t,e){return K.apply(this,arguments)})},{key:"renderTransactionsList",value:function(t){var e=this;return t.map(function(t){return'\n
\n '.concat(e.formatDate(t.date),'\n ').concat(s.ZD(t.description),'\n ').concat(e.formatCurrency(t.amount,t.accountCurrency),"\n
\n ")}).join("")}},{key:"populateTransactionModalDropdowns",value:function(){var t=document.getElementById("transaction-account");if(t&&this.accounts){var e=t.value;t.innerHTML='"),(0,k.ig)(this.accounts,e).forEach(function(e){var n=document.createElement("option");n.value=e.id,n.textContent=(0,k.Jo)(e),t.appendChild(n)}),e&&(t.value=e)}var n=document.getElementById("transfer-to-account");if(n&&this.accounts){var a=n.value;n.innerHTML='"),(0,k.ig)(this.accounts,a).forEach(function(t){var e=document.createElement("option");e.value=t.id,e.textContent=(0,k.Jo)(t),n.appendChild(e)}),a&&(n.value=a)}var r=document.getElementById("transaction-category");if(r&&this.categories){var o=r.value;r.innerHTML='"),s.Vb(r,this.categoryTree||this.categories),o&&(r.value=o)}}},{key:"showTransactionModal",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,a=document.getElementById("transaction-modal");if(a){var r;this._formTransaction=null!=e&&e.id?e:null;var s=document.getElementById("transaction-modal-title");s&&(s.textContent=null!=e&&e.id?(0,i.Tl)("budget","Edit transaction"):(0,i.Tl)("budget","New transaction")),this.populateTransactionModalDropdowns();var c=document.getElementById("transaction-type");if(c){var l=c.querySelector('option[value="transfer"]');e&&l?l.remove():e||l||c.appendChild(new Option((0,i.Tl)("budget","Transfer"),"transfer"))}if(e){document.getElementById("transaction-id").value=e.id||"",(0,u.Mv)("transaction-date",e.date),(0,k.XH)(document.getElementById("transaction-account"),this.accounts,e.accountId),document.getElementById("transaction-type").value=e.type,document.getElementById("transaction-amount").value=e.amount,document.getElementById("transaction-description").value=e.description,document.getElementById("transaction-vendor").value=e.vendor||"",document.getElementById("transaction-category").value=e.categoryId||"",document.getElementById("transaction-notes").value=e.notes||"";var d=document.getElementById("transaction-excluded-from-forecast");d&&(d.checked=!!e.excludedFromForecast),this.setupAttachmentsSection(e.id,(this.accounts||[]).find(function(t){return t.id===e.accountId})||null),this.setupReceiptScan(!1),this.app.renderTransactionTagSelectors(e.categoryId,e.id)}else{document.getElementById("transaction-form").reset(),document.getElementById("transaction-id").value="",(0,u.Mv)("transaction-date",o.rT()),document.getElementById("transaction-type").value="debit",this._pendingAttachments=[],this.setupAttachmentsSection(null),this.setupReceiptScan(!0);var h=document.getElementById("transfer-dest-amount-wrapper");h&&(h.style.display="none");var g=document.getElementById("transfer-dest-amount");g&&(g.value="",g.dataset.userEdited="");var p=document.getElementById("transaction-amount-label");p&&(p.textContent=(0,i.Tl)("budget","Amount"));var f=document.getElementById("transaction-account"),m=n||this._defaultTransactionAccountId();m&&f.querySelector('option[value="'.concat(m,'"]'))&&(f.value=String(m)),this.app.renderTransactionTagSelectors(null,null)}var v=document.getElementById("transaction-category");if(v){var y=v.onchange;v.onchange=function(){y&&y();var e=document.getElementById("transaction-id").value;t.app.renderTransactionTagSelectors(v.value||null,e||null)}}var b=document.getElementById("transaction-type"),w=document.getElementById("transfer-to-account-wrapper"),T=document.getElementById("transfer-dest-amount-wrapper");if(b&&w){var E=function(){var e="transfer"===b.value;w.style.display=e?"block":"none",!e&&T&&(T.style.display="none"),e&&t._checkCrossCurrencyTransfer()};b.onchange=E,E()}this._bindTransferAmountFields(),this._updateAmountStep(),this._refreshFormCategoryOptions(null!=e&&e.id?null!==(r=e.categoryId)&&void 0!==r?r:"":void 0);var x=document.getElementById("transaction-account");x&&!this._categoryScopeBound&&(this._categoryScopeBound=!0,x.addEventListener("change",function(){return t._refreshFormCategoryOptions()})),this.setupInlineSplitToggle(),this._bindDescriptionRule();var S,C=document.getElementById("transaction-extras");C&&(C.open=!(!e||!(e.notes||e.excludedFromForecast||null!==(S=this.app.attachmentCounts)&&void 0!==S&&S[e.id]))),this._setupTypeToggle(),this._syncTypeToggle(),a.style.display="flex",this._keepKeyboardDownWhenViewing(e)}}},{key:"_bindDescriptionRule",value:function(){var t=this,e=document.getElementById("transaction-vendor");e&&!e.dataset.descriptionRule&&(e.dataset.descriptionRule="1",e.addEventListener("input",function(){return t._syncDescriptionRequired()}),e.addEventListener("change",function(){return t._syncDescriptionRequired()})),this._syncDescriptionRequired()}},{key:"_syncDescriptionRequired",value:function(){var t,e,n=document.getElementById("transaction-description");if(n){var a=""===(null!==(t=null===(e=document.getElementById("transaction-vendor"))||void 0===e?void 0:e.value)&&void 0!==t?t:"").trim();n.required=a;var r=document.querySelector('label[for="transaction-description"] .required');r&&(r.hidden=!a)}}},{key:"_formAccount",value:function(){var t,e=null===(t=document.getElementById("transaction-account"))||void 0===t?void 0:t.value;return e&&(this.accounts||[]).find(function(t){return String(t.id)===String(e)})||null}},{key:"_refreshFormCategoryOptions",value:function(){var t,e,n=this,a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:void 0,r=document.getElementById("transaction-category");if(r&&this.categories){var o=this._formAccount(),c=void 0!==a||"1"===(null===(t=r.selectedOptions)||void 0===t||null===(t=t[0])||void 0===t?void 0:t.dataset.unavailable),l=void 0!==a?String(null!=a?a:""):r.value,u=(0,k.hM)(this.categories,[o],[l]);if(r.innerHTML='"),s.Vb(r,u?(0,k.QN)(u):this.categoryTree||this.categories),c){var d,h=this._formTransaction,g=h&&String(null!==(d=h.categoryId)&&void 0!==d?d:"")===l?h.categoryName:null;(0,w.Qz)(r,l,g?(0,w.pC)(g):null)}else r.value=l;var p=null===(e=document.getElementById("transaction-type"))||void 0===e?void 0:e.value;document.querySelectorAll("#inline-splits-container .inline-split-category").forEach(function(t){var e,a=t.value,r=(null===(e=t.selectedOptions)||void 0===e||null===(e=e[0])||void 0===e?void 0:e.dataset.categoryName)||null;t.innerHTML='")+n.app.getCategoryOptions(a?parseInt(a,10):null,p,o,r),t.value=a})}}},{key:"_keepKeyboardDownWhenViewing",value:function(t){var e,n;if(null!=t&&t.id&&null!==(e=(n=window).matchMedia)&&void 0!==e&&e.call(n,Le).matches){var a=document.getElementById("transaction-modal-title");a&&(a.setAttribute("tabindex","-1"),a.focus({preventScroll:!0}))}}},{key:"_defaultTransactionAccountId",value:function(){var t,e=(0,k.HB)(this.accounts),n=function(t){return e.some(function(e){return String(e.id)===String(t)})},a=null===(t=document.getElementById("filter-account"))||void 0===t?void 0:t.value;if(a&&n(a))return a;var r=null;try{r=window.localStorage.getItem("budget.lastTransactionAccountId")}catch(t){}return r&&n(r)?r:1===e.length?e[0].id:null}},{key:"_setupTypeToggle",value:function(){var t=this;if(!this._typeToggleBound){var e=document.getElementById("transaction-type-toggle"),n=document.getElementById("transaction-type");if(e&&n){this._typeToggleBound=!0;var a=function(e){e&&!e.hidden&&n.value!==e.dataset.value&&(n.value=e.dataset.value,n.dispatchEvent(new Event("change")),t._syncTypeToggle())};e.addEventListener("click",function(t){return a(t.target.closest("button[data-value]"))}),e.addEventListener("keydown",function(t){if(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"].includes(t.key)){t.preventDefault();var r=ve(e.querySelectorAll("button[data-value]")).filter(function(t){return!t.hidden}),i=r.findIndex(function(t){return t.dataset.value===n.value}),o=r[(i+("ArrowRight"===t.key||"ArrowDown"===t.key?1:-1)+r.length)%r.length];a(o),null==o||o.focus()}})}}}},{key:"_syncTypeToggle",value:function(){var t=document.getElementById("transaction-type-toggle"),e=document.getElementById("transaction-type");t&&e&&t.querySelectorAll("button[data-value]").forEach(function(t){var n=!!e.querySelector('option[value="'.concat(t.dataset.value,'"]')),a=n&&e.value===t.dataset.value;t.hidden=!n,t.classList.toggle("active",a),t.setAttribute("aria-checked",a?"true":"false"),t.tabIndex=a||!e.value&&"debit"===t.dataset.value?0:-1})}},{key:"editTransaction",value:($=Se(Te().m(function t(e){var n,a,r;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(!(a=this.transactions.find(function(t){return t.id===e}))&&null!==(n=this.app.accountsModule)&&void 0!==n&&n.accountTransactions&&(a=this.app.accountsModule.accountTransactions.find(function(t){return t.id===e})),a){t.n=4;break}return t.p=1,t.n=2,(0,T.n)("/apps/budget/api/transactions/".concat(e));case 2:a=t.v,t.n=4;break;case 3:return t.p=3,r=t.v,console.error("Failed to fetch transaction for editing:",r),(0,c.Qg)((0,i.Tl)("budget","Failed to load transaction")),t.a(2);case 4:a&&this.showTransactionModal(a);case 5:return t.a(2)}},t,this,[[1,3]])})),function(t){return $.apply(this,arguments)})},{key:"duplicateTransaction",value:(Q=Se(Te().m(function t(e){var n,a,r,o;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(!(a=this.transactions.find(function(t){return t.id===e}))&&null!==(n=this.app.accountsModule)&&void 0!==n&&n.accountTransactions&&(a=this.app.accountsModule.accountTransactions.find(function(t){return t.id===e})),a){t.n=4;break}return t.p=1,t.n=2,(0,T.n)("/apps/budget/api/transactions/".concat(e));case 2:a=t.v,t.n=4;break;case 3:return t.p=3,o=t.v,console.error("Failed to fetch transaction for duplicating:",o),(0,c.Qg)((0,i.Tl)("budget","Failed to load transaction")),t.a(2);case 4:a&&(r=be(be({},a),{},{id:null}),this.showTransactionModal(r));case 5:return t.a(2)}},t,this,[[1,3]])})),function(t){return Q.apply(this,arguments)})},{key:"setupReceiptScan",value:(Y=Se(Te().m(function t(e){var n,a,r,i,o,s,c,l,u=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.getElementById("transaction-scan-group")){t.n=1;break}return t.a(2);case 1:if(this._scannedReceiptFile=null,this._allowNegativeRemainder=!1,this.clearScanResult(),void 0!==this._ocrAvailable){t.n=7;break}return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/receipts/ocr-status");case 3:if(l=a=t.v,!(c=null!==l)){t.n=4;break}c=void 0!==a;case 4:if(!(s=c)){t.n=5;break}s=a.available;case 5:this._ocrAvailable=!!s,t.n=7;break;case 6:t.p=6,t.v,this._ocrAvailable=!1;case 7:if(n.style.display=this._ocrAvailable?"":"none",this._ocrAvailable){t.n=8;break}return t.a(2);case 8:if(e&&(r=document.getElementById("transaction-extras"))&&(r.open=!0),this._scanIsNewTransaction=e,!this._scanBound){t.n=9;break}return t.a(2);case 9:this._scanBound=!0,i=document.getElementById("transaction-scan-drop"),o=document.getElementById("transaction-scan-input"),i.addEventListener("click",function(){return o.click()}),i.addEventListener("keydown",function(t){"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),o.click())}),o.addEventListener("change",function(){o.files[0]&&u.scanReceipt(o.files[0]),o.value=""}),["dragenter","dragover"].forEach(function(t){return i.addEventListener(t,function(t){t.preventDefault(),i.classList.add("is-over")})}),["dragleave","drop"].forEach(function(t){return i.addEventListener(t,function(t){t.preventDefault(),i.classList.remove("is-over")})}),i.addEventListener("drop",function(t){var e,n=null===(e=t.dataTransfer)||void 0===e||null===(e=e.files)||void 0===e?void 0:e[0];n&&u.scanReceipt(n)});case 10:return t.a(2)}},t,this,[[2,6]])})),function(t){return Y.apply(this,arguments)})},{key:"clearScanResult",value:function(){var t=document.getElementById("transaction-scan-result");t&&(t.hidden=!0,t.textContent="");var e=document.getElementById("transaction-scan-drop");e&&e.classList.remove("has-file")}},{key:"setScanBusy",value:function(t){var e=document.getElementById("transaction-scan-drop");e&&(e.classList.toggle("is-busy",t),e.querySelector(".receipt-scan-idle").hidden=t,e.querySelector(".receipt-scan-busy").hidden=!t)}},{key:"scanReceipt",value:(Z=Se(Te().m(function t(e){var n,a,r,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return this.clearScanResult(),this.setScanBusy(!0),t.p=1,(a=new FormData).append("image",e),t.n=2,(0,T.n)("/apps/budget/api/receipts/extract",{method:"POST",body:a,errorMessage:(0,i.Tl)("budget","The receipt could not be read")});case 2:r=t.v,o=this.applyReceiptDraft(r),this._scannedReceiptFile=e,null===(n=document.getElementById("transaction-scan-drop"))||void 0===n||n.classList.add("has-file"),this.showScanResult(r,o),t.n=4;break;case 3:t.p=3,s=t.v,(0,c.Qg)(s.message||(0,i.Tl)("budget","The receipt could not be read"));case 4:return t.p=4,this.setScanBusy(!1),t.f(4);case 5:return t.a(2)}},t,this,[[1,3,4,5]])})),function(t){return Z.apply(this,arguments)})},{key:"applyReceiptDraft",value:function(t){var e=[],n=this._scanIsNewTransaction,a=function(t,a,r){t&&null!=a&&""!==a&&(n||""===t.value)&&(t.value=a,t.dispatchEvent(new Event("change",{bubbles:!0})),e.push(r))};if(t.date){var r=document.getElementById("transaction-date");r&&(n||""===r.value)&&((0,u.Mv)("transaction-date",t.date),e.push((0,i.Tl)("budget","date")))}if(t.total&&a(document.getElementById("transaction-amount"),t.total,(0,i.Tl)("budget","amount")),t.merchant&&(a(document.getElementById("transaction-description"),t.merchant,(0,i.Tl)("budget","description")),a(document.getElementById("transaction-vendor"),t.merchant,(0,i.Tl)("budget","vendor"))),t.suggestedCategoryId){var o=document.getElementById("transaction-category");o&&ve(o.options).some(function(e){return e.value===String(t.suggestedCategoryId)})&&a(o,String(t.suggestedCategoryId),(0,i.Tl)("budget","category"))}return e}},{key:"receiptSplitPlan",value:function(t){var e=Number(t.total),n=(t.lineItems||[]).map(function(t){var e,n;return{description:String(null!==(e=t.description)&&void 0!==e?e:"").slice(0,255),amount:Number(t.amount),suggestedCategoryId:null!==(n=t.suggestedCategoryId)&&void 0!==n?n:null}}).filter(function(t){return Number.isFinite(t.amount)&&t.amount>0});if(n.length<2||!Number.isFinite(e)||e<=0)return null;var a=function(t){return Math.round(100*t)},r=n.reduce(function(t,e){return t+a(e.amount)},0),i=a(e),o=a(Number(t.tax)||0),s=a(Math.abs(Number(t.discount)||0)),c=s>0?Math.abs(Number(t.discount)):null,l=o>0?Number(t.tax):null;return r===i?{rows:n,tax:null,discount:null}:o>0&&r+o===i?{rows:n,tax:l,discount:null}:s>0&&r-s===i?{rows:n,tax:null,discount:c}:s>0&&o>0&&r-s+o===i?{rows:n,tax:l,discount:c}:null}},{key:"applyReceiptSplits",value:function(t){var e=this,n=document.getElementById("transaction-split-toggle"),a=document.getElementById("inline-splits-section"),r=document.getElementById("inline-splits-container"),o=document.getElementById("transaction-category-group");if(n&&a&&r){n.checked=!0,a.style.display="",o&&(o.style.display="none"),this._allowNegativeRemainder=null!==t.discount,r.innerHTML="";var s=ve(t.rows);null!==t.discount&&s.push({description:(0,i.Tl)("budget","Savings / discount"),amount:-t.discount}),null!==t.tax&&s.push({description:(0,i.Tl)("budget","VAT / tax"),amount:t.tax}),s.forEach(function(t,n){e.addInlineSplitRow(0===n,{amount:"",categoryId:null,description:t.description})});var l=ve(r.querySelectorAll(".split-row"));l.forEach(function(t,e){if(!(e>=l.length-1)){var n=t.querySelector(".inline-split-amount");n&&(n.value=s[e].amount.toFixed(2),s[e].amount<0&&n.removeAttribute("min"))}});var u=0;l.forEach(function(n,a){if(!(a>=t.rows.length)){var r=n.querySelector(".inline-split-category");r&&(e.preselectSuggestedCategory(r,t.rows[a].suggestedCategoryId)&&u++,e.offerRememberItemCategory(n,r,t.rows[a]))}}),this.refreshInlineSplitRows(),this.recomputeRemainderRow(),(0,c.Te)(u?(0,i.Tl)("budget","Split into {count} lines from the receipt. Your rules set a category on {suggested} of them; check them and set the rest.",{count:s.length,suggested:u}):(0,i.Tl)("budget","Split into {count} lines from the receipt. Set a category on each.",{count:s.length}))}}},{key:"preselectSuggestedCategory",value:function(t,e){if(null==e)return!1;var n=ve(t.options).find(function(t){return t.value===String(e)&&!t.disabled});return!!n&&(t.value=n.value,!0)}},{key:"offerRememberItemCategory",value:function(t,e,n){var a=t.querySelector(".split-category-field");if(a&&n.description){var r=document.createElement("button");r.type="button",r.className="receipt-remember-btn",r.textContent=(0,i.Tl)("budget","Remember"),r.title=(0,i.Tl)("budget",'Use this category for "{item}" on future receipts',{item:n.description}),r.hidden=!0,a.appendChild(r);var o=null!==n.suggestedCategoryId?String(n.suggestedCategoryId):"";e.addEventListener("change",function(){r.hidden=""===e.value||e.value===o,r.disabled=!1,r.textContent=(0,i.Tl)("budget","Remember")}),r.addEventListener("click",Se(Te().m(function t(){var a,s,l,u,d;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(""!==(a=e.value)){t.n=1;break}return t.a(2);case 1:return r.disabled=!0,t.p=2,t.n=3,(0,T.n)("/apps/budget/api/import-rules");case 3:return s=t.v,l=he(s,n.description),u=de(n.description,a,(0,i.Tl)("budget","Receipt items")),t.n=4,(0,T.n)(l?"/apps/budget/api/import-rules/".concat(l.id):"/apps/budget/api/import-rules",{method:l?"PUT":"POST",body:u,errorMessage:(0,i.Tl)("budget","Could not save the rule")});case 4:o=a,r.textContent=(0,i.Tl)("budget","Remembered"),t.n=6;break;case 5:t.p=5,d=t.v,r.disabled=!1,(0,c.Qg)((null==d?void 0:d.message)||(0,i.Tl)("budget","Could not save the rule"));case 6:return t.a(2)}},t,null,[[2,5]])})))}}},{key:"showScanResult",value:function(t,e){var n,a,r=this,o=document.getElementById("transaction-scan-result");if(o){var s=[];s.push(e.length?(0,i.Tl)("budget","Filled in: {fields}. Check them before saving.",{fields:e.join(", ")}):(0,i.Tl)("budget","Nothing was filled in — the fields already had values. Clear one and scan again to use the receipt."));var c=(null===(n=t.lineItems)||void 0===n?void 0:n.length)||0;c&&s.push((0,i.Tl)("budget","Read {count} items from the receipt.",{count:c})),null!==(a=t.warnings)&&void 0!==a&&a.includes("line-items-sum-mismatch")&&s.push((0,i.Tl)("budget","The items do not add up to the total — worth a look.")),t.currency&&""!==t.currency&&s.push((0,i.Tl)("budget","Receipt currency: {currency}.",{currency:t.currency})),s.push((0,i.Tl)("budget","The photo will be attached when you save.")),o.textContent=s.join(" ");var l=this.receiptSplitPlan(t);if(!l&&c>=2&&(o.textContent+=" "+(0,i.Tl)("budget","These items cannot be split individually: they do not add up to the total, so the parts would not balance.")),l){var u=l.rows.length+(null!==l.tax?1:0)+(null!==l.discount?1:0),d=document.createElement("button");d.type="button",d.className="secondary receipt-scan-split-btn",d.textContent=(0,i.Tl)("budget","Split into {count} lines",{count:u});var h=[];null!==l.discount&&h.push((0,i.Tl)("budget","the savings as a negative line")),null!==l.tax&&h.push((0,i.Tl)("budget","the tax as its own line")),d.title=h.length?(0,i.Tl)("budget","One line per item, plus {extras}",{extras:h.join((0,i.Tl)("budget"," and "))}):(0,i.Tl)("budget","One line per item on the receipt"),d.addEventListener("click",function(){r.applyReceiptSplits(l),d.disabled=!0}),o.appendChild(document.createElement("br")),o.appendChild(d)}o.hidden=!1}}},{key:"setupAttachmentsSection",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,a=document.getElementById("transaction-attachments-group");if(a){if(t&&(0,k.GF)(n))return a.style.display="none",void(this._attachmentTxId=null);if(a.style.display="",this._attachmentTxId=t,!this._attachmentsBound){var r,o;this._attachmentsBound=!0;var s=document.getElementById("attachment-file-input");null===(r=document.getElementById("attachment-upload-btn"))||void 0===r||r.addEventListener("click",function(){return null==s?void 0:s.click()}),null==s||s.addEventListener("change",Se(Te().m(function t(){var n,a,r,i,o,c,l;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e._attachmentTxId){t.n=1;break}n=me(s.files);try{for(n.s();!(a=n.n()).done;)r=a.value,e._pendingAttachments.push({kind:"file",file:r,name:r.name})}catch(t){n.e(t)}finally{n.f()}return s.value="",e.renderPendingAttachments(),t.a(2);case 1:i=me(s.files),t.p=2,i.s();case 3:if((o=i.n()).done){t.n=5;break}return c=o.value,t.n=4,e.uploadAttachment(e._attachmentTxId,c);case 4:t.n=3;break;case 5:t.n=7;break;case 6:t.p=6,l=t.v,i.e(l);case 7:return t.p=7,i.f(),t.f(7);case 8:return s.value="",t.n=9,e.loadAttachments(e._attachmentTxId);case 9:return t.a(2)}},t,null,[[2,6,7,8]])}))),null===(o=document.getElementById("attachment-pick-btn"))||void 0===o||o.addEventListener("click",function(){OC.dialogs.filepicker((0,i.Tl)("budget","Select receipt"),function(){var t=Se(Te().m(function t(n){return Te().w(function(t){for(;;)switch(t.n){case 0:if(e._attachmentTxId){t.n=1;break}return e._pendingAttachments.push({kind:"path",path:n,name:n.split("/").pop()||n}),e.renderPendingAttachments(),t.a(2);case 1:return t.n=2,e.attachExistingFile(e._attachmentTxId,n);case 2:return t.n=3,e.loadAttachments(e._attachmentTxId);case 3:return t.a(2)}},t)}));return function(e){return t.apply(this,arguments)}}(),!1,["image/*","application/pdf"],!0)})}t?this.loadAttachments(t):this.renderPendingAttachments()}}},{key:"renderPendingAttachments",value:function(){var t=this,e=document.getElementById("transaction-attachments-list");e&&(this._pendingAttachments.length?(e.innerHTML=this._pendingAttachments.map(function(t,e){return'\n
\n ').concat("path"===t.kind?"🗂️":"📄","\n ").concat(s.ZD(t.name),'\n ').concat((0,i.Tl)("budget","on save"),'\n \n
')}).join(""),e.querySelectorAll(".attachment-remove").forEach(function(e){e.addEventListener("click",function(){t._pendingAttachments.splice(parseInt(e.dataset.pendingIndex),1),t.renderPendingAttachments()})})):e.innerHTML=''.concat((0,i.Tl)("budget","No receipts yet — they are attached when you save."),""))}},{key:"flushPendingAttachments",value:(G=Se(Te().m(function t(e){var n,a,r,i,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:n=0,a=me(this._pendingAttachments),t.p=1,a.s();case 2:if((r=a.n()).done){t.n=10;break}if(i=r.value,t.p=3,"path"!==i.kind){t.n=5;break}return t.n=4,this.attachExistingFile(e,i.path);case 4:o=t.v,t.n=7;break;case 5:return t.n=6,this.uploadAttachment(e,i.file);case 6:o=t.v;case 7:o||n++,t.n=9;break;case 8:t.p=8,t.v,n++;case 9:t.n=2;break;case 10:t.n=12;break;case 11:t.p=11,s=t.v,a.e(s);case 12:return t.p=12,a.f(),t.f(12);case 13:return this._pendingAttachments=[],t.a(2,n)}},t,this,[[3,8],[1,11,12,13]])})),function(t){return G.apply(this,arguments)})},{key:"loadAttachments",value:(U=Se(Te().m(function t(e){var n,a,r,o=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.getElementById("transaction-attachments-list")){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/attachments"));case 2:a=t.v,n.innerHTML=a.map(function(t){var e=t.isImage&&!t.missing?''):"📄",n=s.ZD(t.fileName||(0,i.Tl)("budget","Receipt")),a=t.missing?'').concat(n,""):'').concat(n,"");return'\n
\n ').concat(e,"\n ").concat(a,'\n \n
')}).join("")||''.concat((0,i.Tl)("budget","No receipts attached"),""),n.querySelectorAll(".attachment-remove").forEach(function(t){t.addEventListener("click",Se(Te().m(function n(){return Te().w(function(n){for(;;)switch(n.n){case 0:return n.n=1,o.detachAttachment(e,parseInt(t.dataset.attachmentId));case 1:return n.n=2,o.loadAttachments(e);case 2:return n.a(2)}},n)})))}),t.n=4;break;case 3:t.p=3,r=t.v,console.error("Failed to load attachments:",r),n.innerHTML=''.concat((0,i.Tl)("budget","Failed to load attachments"),"");case 4:return t.a(2)}},t,null,[[1,3]])})),function(t){return U.apply(this,arguments)})},{key:"uploadAttachment",value:(W=Se(Te().m(function t(e,n){var a,r;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,(a=new FormData).append("file",n),t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/attachments/upload"),{method:"POST",body:a,errorMessage:(0,i.Tl)("budget","Failed to upload receipt")});case 1:return this.app.attachmentCounts=null,t.a(2,!0);case 2:return t.p=2,r=t.v,(0,c.Qg)(r.message||(0,i.Tl)("budget","Failed to upload receipt")),t.a(2,!1)}},t,this,[[0,2]])})),function(t,e){return W.apply(this,arguments)})},{key:"attachExistingFile",value:(q=Se(Te().m(function t(e,n){var a;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/attachments"),{method:"POST",body:{path:n},errorMessage:(0,i.Tl)("budget","Failed to attach file")});case 1:return this.app.attachmentCounts=null,t.a(2,!0);case 2:return t.p=2,a=t.v,(0,c.Qg)(a.message||(0,i.Tl)("budget","Failed to attach file")),t.a(2,!1)}},t,this,[[0,2]])})),function(t,e){return q.apply(this,arguments)})},{key:"detachAttachment",value:(V=Se(Te().m(function t(e,n){return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/attachments/").concat(n),{method:"DELETE"});case 1:this.app.attachmentCounts=null,t.n=3;break;case 2:t.p=2,t.v,(0,c.Qg)((0,i.Tl)("budget","Failed to remove attachment"));case 3:return t.a(2)}},t,this,[[0,2]])})),function(t,e){return V.apply(this,arguments)})},{key:"saveTransaction",value:function(){var t=this;return(0,ee.O)("transaction-save",document.querySelector('#transaction-form [type="submit"]'),function(){return t._saveTransaction()})}},{key:"_saveTransaction",value:(z=Se(Te().m(function t(){var e,n,a,r,o,s,u,d,h,g,p,f,m,v,y,b,w,k,E,x,S,C,I,A,_,M,D,B,L,P,O,F,R,N,j,H;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.getElementById("transaction-id").value,a=document.getElementById("transaction-date").value,r=parseInt(document.getElementById("transaction-account").value),!n&&r)try{window.localStorage.setItem("budget.lastTransactionAccountId",String(r))}catch(t){}if(o=document.getElementById("transaction-type").value,s=parseFloat(document.getElementById("transaction-amount").value),!n){t.n=3;break}if(null==(d=null===(u=this.transactions)||void 0===u?void 0:u.find(function(t){return t.id===parseInt(n)}))||!d.reconciled){t.n=3;break}if(h=parseFloat(d.amount)!==s||d.type!==o||d.accountId!==r||d.date!==a,!(N=h)){t.n=2;break}return t.n=1,(0,l.ZD)((0,i.Tl)("budget","This transaction was reconciled against a bank statement. Changing its amount, type, account or date will make past reconciliations no longer match. Continue?"));case 1:N=!t.v;case 2:if(!N){t.n=3;break}return t.a(2);case 3:if(g=document.getElementById("transaction-description").value,p=document.getElementById("transaction-vendor").value,f=document.getElementById("transaction-category").value,m=document.getElementById("transaction-notes").value,v=(null===(e=document.getElementById("transaction-excluded-from-forecast"))||void 0===e?void 0:e.checked)||!1,y=Array.from(document.querySelectorAll('#transaction-tags-container input[type="checkbox"]:checked')).map(function(t){return parseInt(t.value)}),"transfer"!==o||n){t.n=16;break}if(b=parseInt(document.getElementById("transfer-to-account").value)){t.n=4;break}return(0,c.I9)((0,i.Tl)("budget","Please select destination account")),t.a(2);case 4:if(b!==r){t.n=5;break}return(0,c.I9)((0,i.Tl)("budget","Cannot transfer to same account")),t.a(2);case 5:return t.p=5,t.n=6,(0,T.n)("/apps/budget/api/transactions",{method:"POST",body:{date:a,accountId:r,type:"debit",amount:s,description:g,vendor:p||null,categoryId:f?parseInt(f):null,notes:m||null},errorMessage:"Failed to create transfer debit transaction"});case 6:return w=t.v,k=w.id,E=document.getElementById("transfer-dest-amount-wrapper"),x=document.getElementById("transfer-dest-amount"),S="none"!==(null==E?void 0:E.style.display)&&null!=x&&x.value?parseFloat(x.value):s,t.n=7,(0,T.n)("/apps/budget/api/transactions",{method:"POST",body:{date:a,accountId:b,type:"credit",amount:S,description:g,vendor:p||null,categoryId:f?parseInt(f):null,notes:m||null},errorMessage:"Failed to create transfer credit transaction"});case 7:return C=t.v,I=C.id,t.n=8,(0,T.n)("/apps/budget/api/transactions/".concat(k,"/link/").concat(I),{method:"POST",errorMessage:"Failed to link transfer transactions"});case 8:if(!(y.length>0)){t.n=10;break}return t.n=9,this.app.tagSetsModule.saveTransactionTags(k,y);case 9:return t.n=10,this.app.tagSetsModule.saveTransactionTags(I,y);case 10:return(0,c.Te)((0,i.Tl)("budget","Transfer created successfully")),this.app.hideModals(),t.n=11,this.app.loadTransactions();case 11:return t.n=12,this.app.loadAccounts();case 12:return t.n=13,this.app.refreshCurrentAccountView();case 13:if(""!==window.location.hash&&"#/dashboard"!==window.location.hash){t.n=14;break}return t.n=14,this.app.loadDashboard();case 14:return t.a(2);case 15:return t.p=15,j=t.v,console.error("Transfer creation failed:",j),(0,c.Qg)(j.message||(0,i.Tl)("budget","Failed to create transfer")),t.a(2);case 16:if(A={date:a,accountId:r,type:o,amount:s,description:g,vendor:p||null,categoryId:f?parseInt(f):null,notes:m||null,excludedFromForecast:v},null==(_=document.getElementById("transaction-split-toggle"))||!_.checked){t.n=17;break}if((M=this.validateInlineSplits()).ok){t.n=17;break}return(0,c.Qg)(M.message),t.a(2);case 17:if(D=this._editedTransaction(n),B=!(!D||!D.isSplit&&!D.is_split||null!=_&&_.checked),t.p=18,P=null,!n){t.n=21;break}if(!B){t.n=19;break}return t.n=19,(0,T.n)("/apps/budget/api/transactions/".concat(n,"/splits"),{method:"DELETE",body:{categoryId:A.categoryId},errorMessage:(0,i.Tl)("budget","Failed to unsplit transaction")});case 19:return t.n=20,(0,T.n)("/apps/budget/api/transactions/".concat(n),{method:"PUT",body:A,errorMessage:(0,i.Tl)("budget","Failed to save transaction")});case 20:t.n=23;break;case 21:return t.n=22,(0,T.n)("/apps/budget/api/transactions",{method:"POST",body:A,errorMessage:(0,i.Tl)("budget","Failed to save transaction")});case 22:P=t.v;case 23:if(O=(null===(L=P)||void 0===L?void 0:L.id)||parseInt(n),!(!n&&y.length>0&&O)){t.n=24;break}return t.n=24,this.app.tagSetsModule.saveTransactionTags(O,y);case 24:if(null==(F=document.getElementById("transaction-split-toggle"))||!F.checked||!O){t.n=25;break}return t.n=25,this.saveInlineSplits(O);case 25:if(!O){t.n=27;break}return this._scannedReceiptFile&&(this._pendingAttachments.push({kind:"file",file:this._scannedReceiptFile,name:this._scannedReceiptFile.name}),this._scannedReceiptFile=null),t.n=26,this.flushPendingAttachments(O);case 26:(R=t.v)>0&&(0,c.I9)((0,i.Tl)("budget","The transaction was saved, but {count} receipt(s) could not be attached",{count:R}));case 27:return(0,c.Te)(n?(0,i.Tl)("budget","Transaction updated"):(0,i.Tl)("budget","Transaction created")),this.app.hideModals(),t.n=28,this.app.loadTransactions();case 28:return t.n=29,this.app.loadAccounts();case 29:return t.n=30,this.app.refreshCurrentAccountView();case 30:if(""!==window.location.hash&&"#/dashboard"!==window.location.hash){t.n=31;break}return t.n=31,this.app.loadDashboard();case 31:t.n=33;break;case 32:t.p=32,H=t.v,console.error("Failed to save transaction:",H),(0,c.Qg)(H.message||(0,i.Tl)("budget","Failed to save transaction"));case 33:return t.a(2)}},t,this,[[18,32],[5,15]])})),function(){return z.apply(this,arguments)})},{key:"_editedTransaction",value:function(t){var e,n,a=parseInt(t);return a?(null===(e=this._formTransaction)||void 0===e?void 0:e.id)===a?this._formTransaction:(null===(n=this.transactions)||void 0===n?void 0:n.find(function(t){return t.id===a}))||null:null}},{key:"setupInlineSplitToggle",value:function(){var t,e=this,n=document.getElementById("transaction-split-toggle"),a=document.getElementById("inline-splits-section"),r=document.getElementById("transaction-category-group"),i=document.getElementById("split-toggle-group");if(n&&a){var o=null===(t=document.getElementById("transaction-id"))||void 0===t?void 0:t.value,s=!!o,c=document.getElementById("transaction-type"),l="transfer"===(null==c?void 0:c.value),u=this._editedTransaction(o),d=(null==u?void 0:u.isSplit)||(null==u?void 0:u.is_split);if(n.checked=!1,this.hideInlineSplits(),i&&(i.style.display=l?"none":""),s&&d&&(n.checked=!0,a.style.display="",r&&(r.style.display="none"),this.loadExistingSplits(parseInt(o))),c){var h=c.onchange;c.onchange=function(){h&&h(),i&&(i.style.display="transfer"===c.value?"none":""),"transfer"===c.value&&n.checked&&(n.checked=!1,n.dispatchEvent(new Event("change")))}}n.onchange=function(){n.checked?(a.style.display="",r&&(r.style.display="none"),e.initInlineSplitRows()):e.hideInlineSplits()};var g=document.getElementById("transaction-amount");g&&g.addEventListener("input",function(){return e.recomputeRemainderRow()});var p=document.getElementById("inline-add-split-btn");p&&(p.onclick=function(){return e.addInlineSplitRow()})}}},{key:"hideInlineSplits",value:function(){var t=document.getElementById("inline-splits-section"),e=document.getElementById("transaction-category-group"),n=document.getElementById("inline-splits-container");t&&(t.style.display="none"),e&&(e.style.display=""),n&&(n.innerHTML=""),this.updateInlineSplitRemaining()}},{key:"initInlineSplitRows",value:function(){var t=document.getElementById("inline-splits-container");t&&(this._allowNegativeRemainder=!1,t.innerHTML="",this.addInlineSplitRow(!0),this.addInlineSplitRow(!1),this.refreshInlineSplitRows())}},{key:"addInlineSplitRow",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,a=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).defer,r=void 0!==a&&a,o=document.getElementById("inline-splits-container");if(o){var c=document.getElementById("transaction-type"),l=(null==c?void 0:c.value)||"debit",u=document.createElement("div");u.className="split-row";var d=n?Number(n.amount):null,h=null!==d&&d<0?"":'min="0.01"';u.innerHTML='\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n '),u.querySelector(".inline-split-amount").addEventListener("input",function(){t.recomputeRemainderRow()}),u.querySelector(".split-remove-btn").addEventListener("click",function(e){e.currentTarget.classList.contains("disabled")||(u.remove(),t.refreshInlineSplitRows())}),o.appendChild(u),r||this.refreshInlineSplitRows()}}},{key:"updateInlineSplitRemaining",value:function(){var t,e=parseFloat(null===(t=document.getElementById("transaction-amount"))||void 0===t?void 0:t.value)||0,n=document.querySelectorAll("#inline-splits-container .split-row"),a=0;n.forEach(function(t){var e;a+=parseFloat(null===(e=t.querySelector(".inline-split-amount"))||void 0===e?void 0:e.value)||0});var r=e-a,o=document.getElementById("inline-split-remaining");if(o){var s=Math.abs(r)<.01;o.textContent=s?(0,i.Tl)("budget","Fully allocated"):(0,i.Tl)("budget","Remaining: {amount}",{amount:r.toFixed(2)}),o.style.color=s?(0,g.PJ)("positive","#4caf50"):"var(--budget-color-negative)"}}},{key:"refreshInlineSplitRows",value:function(){var t=Array.from(document.querySelectorAll("#inline-splits-container .split-row"));t.forEach(function(e,n){var a=e.querySelector(".inline-split-amount"),r=e.querySelector(".split-amount-field label"),o=t.length>=2&&n===t.length-1;a.readOnly=o,a.classList.toggle("inline-split-remainder",o),a.title=o?(0,i.Tl)("budget","Auto-calculated from the transaction total minus the other splits"):"",r&&(r.textContent=o?(0,i.Tl)("budget","Amount (remaining)"):(0,i.Tl)("budget","Amount"))}),this.recomputeRemainderRow()}},{key:"recomputeRemainderRow",value:function(){var t=Array.from(document.querySelectorAll("#inline-splits-container .split-row"));if(t.length>=2){var e,n=parseFloat(null===(e=document.getElementById("transaction-amount"))||void 0===e?void 0:e.value)||0,a=t[t.length-1].querySelector(".inline-split-amount"),r=0;t.slice(0,-1).forEach(function(t){var e;r+=parseFloat(null===(e=t.querySelector(".inline-split-amount"))||void 0===e?void 0:e.value)||0});var i=Math.round(100*(n-r))/100;a.value=i>0||this._allowNegativeRemainder?i.toFixed(2):"0.00"}this.updateInlineSplitRemaining()}},{key:"validateInlineSplits",value:function(){var t,e=parseFloat(null===(t=document.getElementById("transaction-amount"))||void 0===t?void 0:t.value)||0,n=Array.from(document.querySelectorAll("#inline-splits-container .split-row .inline-split-amount")).map(function(t){return parseFloat(t.value)}).filter(function(t){return Number.isFinite(t)&&Math.abs(t)>=.005});if(n.length<2)return{ok:!1,message:(0,i.Tl)("budget","A split needs at least two parts with an amount.")};var a=Math.round(100*n.reduce(function(t,e){return t+e},0))/100;return Math.abs(a-e)>=.01?{ok:!1,message:(0,i.Tl)("budget","Split amounts must add up to the transaction total ({total}).",{total:e.toFixed(2)})}:{ok:!0}}},{key:"loadExistingSplits",value:(H=Se(Te().m(function t(e){var n,a,r,i=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.getElementById("inline-splits-container")){t.n=1;break}return t.a(2);case 1:return n.innerHTML="",t.p=2,t.n=3,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/splits")).catch(function(){return null});case 3:if(a=t.v){t.n=4;break}return t.a(2);case 4:a.length>0?(this._allowNegativeRemainder=a.some(function(t){return Number(t.amount)<0}),a.forEach(function(t,e){i.addInlineSplitRow(0===e,t,{defer:!0})})):(this.addInlineSplitRow(!0),this.addInlineSplitRow(!1)),t.n=6;break;case 5:t.p=5,r=t.v,console.error("Failed to load splits:",r),this.addInlineSplitRow(!0),this.addInlineSplitRow(!1);case 6:this.refreshInlineSplitRows();case 7:return t.a(2)}},t,this,[[2,5]])})),function(t){return H.apply(this,arguments)})},{key:"saveInlineSplits",value:(j=Se(Te().m(function t(e){var n,a,r,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.querySelectorAll("#inline-splits-container .split-row"),!((a=Array.from(n).map(function(t){var e,n,a;return{amount:parseFloat(null===(e=t.querySelector(".inline-split-amount"))||void 0===e?void 0:e.value),categoryId:parseInt(null===(n=t.querySelector(".inline-split-category"))||void 0===n?void 0:n.value)||null,description:(null===(a=t.querySelector(".inline-split-description"))||void 0===a||null===(a=a.value)||void 0===a?void 0:a.trim())||null}}).filter(function(t){return Number.isFinite(t.amount)&&Math.abs(t.amount)>=.005})).length<2)){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/splits"),{method:"POST",body:{splits:a}});case 2:t.n=4;break;case 3:t.p=3,s=t.v,console.error("Failed to save inline splits:",s),o=s instanceof T.h&&(null===(r=s.data)||void 0===r?void 0:r.error)||"",(0,c.I9)(o?(0,i.Tl)("budget","The transaction was saved, but not split: {reason}",{reason:o}):(0,i.Tl)("budget","The transaction was saved, but its splits could not be stored"));case 4:return t.a(2)}},t,null,[[1,3]])})),function(t){return j.apply(this,arguments)})},{key:"deleteTransaction",value:(N=Se(Te().m(function t(e){var n,a,r,s,u,d,h;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return n=this.transactions.find(function(t){return t.id===e}),a=(0,i.Tl)("budget","Are you sure you want to delete this transaction?"),n&&(s=o.vv(n.amount,null===(r=this.accounts.find(function(t){return t.id===n.accountId}))||void 0===r?void 0:r.currency,this.settings),u="credit"===n.type?(0,i.Tl)("budget","This will decrease the account balance by {amount}.",{amount:s}):(0,i.Tl)("budget","This will increase the account balance by {amount}.",{amount:s}),a="scheduled"===n.status?n.billId?(0,i.Tl)("budget","This is the upcoming payment of a bill, not money that has moved. Deleting it removes the scheduled entry until the bill is next paid; the bill itself stays, and the account balance does not change. Are you sure?"):(0,i.Tl)("budget","This transaction is scheduled and not in the account balance yet, so the balance does not change. Are you sure you want to delete it?"):n.billId?(0,i.Tl)("budget","This transaction was auto-generated from a bill payment.")+"\n\n".concat(u,"\n\n")+(0,i.Tl)("budget","If this is a real payment, deleting it will cause your balance to diverge from your bank statement. Are you sure?"):(0,i.Tl)("budget","Are you sure you want to delete this transaction?")+"\n\n".concat(u)),null!=n&&n.reconciled&&(a+="\n\n"+(0,i.Tl)("budget","This transaction was reconciled against a bank statement. Deleting it will make past reconciliations no longer match.")),null!=n&&n.pensionContribId&&(a+="\n\n"+(0,i.Tl)("budget","This transaction funds a pension contribution. Deleting it will unlink it from that contribution (the contribution itself is kept).")),t.n=1,(0,l.ZD)(a,{destructive:!0});case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.p=3,t.n=4,(0,T.n)("/apps/budget/api/transactions/".concat(e),{method:"DELETE",errorMessage:(0,i.Tl)("budget","Failed to delete transaction")});case 4:t.n=7;break;case 5:if(t.p=5,(d=t.v)instanceof T.h){t.n=6;break}throw d;case 6:return(0,c.Qg)(d.message),t.a(2);case 7:return(0,c.Te)((0,i.Tl)("budget","Transaction deleted")),t.n=8,this.app.loadTransactions();case 8:return t.n=9,this.app.loadAccounts();case 9:return t.n=10,this.app.refreshCurrentAccountView();case 10:if(""!==window.location.hash&&"#/dashboard"!==window.location.hash){t.n=11;break}return t.n=11,this.app.loadDashboard();case 11:t.n=13;break;case 12:t.p=12,h=t.v,console.error("Failed to delete transaction:",h),(0,c.Qg)((0,i.Tl)("budget","Failed to delete transaction"));case 13:return t.a(2)}},t,this,[[3,5],[2,12]])})),function(t){return N.apply(this,arguments)})},{key:"findTransactionMatches",value:(R=Se(Te().m(function t(e){var n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/matches"));case 1:return t.a(2,t.v);case 2:throw t.p=2,n=t.v,console.error("Failed to find matches:",n),n;case 3:return t.a(2)}},t,null,[[0,2]])})),function(t){return R.apply(this,arguments)})},{key:"linkTransactions",value:(F=Se(Te().m(function t(e,n){var a;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/link/").concat(n),{method:"POST"});case 1:return t.a(2,t.v);case 2:throw t.p=2,a=t.v,console.error("Failed to link transactions:",a),a;case 3:return t.a(2)}},t,null,[[0,2]])})),function(t,e){return F.apply(this,arguments)})},{key:"unlinkTransaction",value:(O=Se(Te().m(function t(e){var n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/link"),{method:"DELETE"});case 1:return t.a(2,t.v);case 2:throw t.p=2,n=t.v,console.error("Failed to unlink transaction:",n),n;case 3:return t.a(2)}},t,null,[[0,2]])})),function(t){return O.apply(this,arguments)})},{key:"_updateAmountStep",value:function(){var t=this,e=function(e,n){var a,r=document.getElementById(e);if(r){var i=parseInt(null===(a=document.getElementById(n))||void 0===a?void 0:a.value),s=(t.accounts||[]).find(function(t){return t.id===i}),c=(null==s?void 0:s.currency)||"USD";r.step=o.yM(c,t.settings||{})}};e("transaction-amount","transaction-account"),e("transfer-dest-amount","transfer-to-account")}},{key:"_bindTransferAmountFields",value:function(){var t=this,e=function(t,e,n){var a=document.getElementById(t);a&&!a.dataset.transferFieldsBound&&(a.dataset.transferFieldsBound="1",a.addEventListener(e,n))},n=function(){t._checkCrossCurrencyTransfer(),t._updateAmountStep()};e("transaction-account","change",n),e("transfer-to-account","change",n),e("transaction-amount","input",function(){var e=document.getElementById("transfer-dest-amount");e&&(e.dataset.userEdited=""),t._updateDestAmountFromRate()}),e("transfer-dest-amount","input",function(t){t.target.dataset.userEdited="true"})}},{key:"_checkCrossCurrencyTransfer",value:function(){var t,e,n,a,r=document.getElementById("transfer-dest-amount-wrapper");if(r){var o=parseInt(null===(t=document.getElementById("transaction-account"))||void 0===t?void 0:t.value),s=parseInt(null===(e=document.getElementById("transfer-to-account"))||void 0===e?void 0:e.value);if(o&&s){var c=null===(n=this.accounts)||void 0===n?void 0:n.find(function(t){return t.id===o}),l=null===(a=this.accounts)||void 0===a?void 0:a.find(function(t){return t.id===s});if(c&&l){var u=c.currency||"",d=l.currency||"";if(u&&d&&u!==d){r.style.display="block";var h=document.getElementById("transaction-amount-label"),g=document.getElementById("transfer-dest-amount-label");h&&(h.textContent=(0,i.Tl)("budget","Amount ({currency})",{currency:u})),g&&(g.textContent=(0,i.Tl)("budget","Destination Amount ({currency})",{currency:d})),this._updateDestAmountFromRate()}else{r.style.display="none";var p=document.getElementById("transaction-amount-label");p&&(p.textContent=(0,i.Tl)("budget","Amount"))}}else r.style.display="none"}else r.style.display="none"}}},{key:"_updateDestAmountFromRate",value:(P=Se(Te().m(function t(){var e,n,a,r,i,o,s,c,l,u,d,h,g,p;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(o=this._destRateSeq=(this._destRateSeq||0)+1,(s=document.getElementById("transfer-dest-amount-wrapper"))&&"none"!==s.style.display){t.n=1;break}return t.a(2);case 1:if((c=parseFloat(null===(e=document.getElementById("transaction-amount"))||void 0===e?void 0:e.value))&&!(c<=0)){t.n=2;break}return t.a(2);case 2:if(l=parseInt(null===(n=document.getElementById("transaction-account"))||void 0===n?void 0:n.value),u=parseInt(null===(a=document.getElementById("transfer-to-account"))||void 0===a?void 0:a.value),d=null===(r=this.accounts)||void 0===r?void 0:r.find(function(t){return t.id===l}),h=null===(i=this.accounts)||void 0===i?void 0:i.find(function(t){return t.id===u}),null!=d&&d.currency&&null!=h&&h.currency){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/exchange-rates/convert?from=".concat(d.currency,"&to=").concat(h.currency,"&amount=").concat(c)).catch(function(){return null});case 4:if(g=t.v,o===this._destRateSeq){t.n=5;break}return t.a(2);case 5:g&&(p=document.getElementById("transfer-dest-amount"))&&!p.dataset.userEdited&&(p.value=g.convertedAmount),t.n=7;break;case 6:t.p=6,t.v;case 7:return t.a(2)}},t,this,[[3,6]])})),function(){return P.apply(this,arguments)})},{key:"showMatchingModal",value:(L=Se(Te().m(function t(e){var n,a,r,o,l,u,d,h,g,p,f,m,v,y,b,w=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(r=null===(n=this.transactions)||void 0===n?void 0:n.find(function(t){return t.id===e})){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Transaction not found")),t.a(2);case 1:return o=document.getElementById("matching-modal"),l=o.querySelector(".source-details"),u=document.getElementById("matching-loading"),d=document.getElementById("matching-empty"),h=document.getElementById("matching-list"),g=null===(a=this.accounts)||void 0===a?void 0:a.find(function(t){return t.id===r.accountId}),p=r.accountCurrency||(null==g?void 0:g.currency)||this.getPrimaryCurrency(),f="credit"===r.type?"positive":"negative",l.querySelector(".source-date").textContent=this.formatDate(r.date),l.querySelector(".source-description").textContent=r.description,l.querySelector(".source-amount").textContent=this.formatCurrency(r.amount,p),l.querySelector(".source-amount").className="source-amount ".concat(f),l.querySelector(".source-account").textContent=(null==g?void 0:g.name)||(0,i.Tl)("budget","Unknown Account"),o.dataset.transactionId=e,m=document.getElementById("matching-convert-account"),v=document.getElementById("matching-convert"),m&&v&&(y=(0,k.HB)(this.accounts).filter(function(t){return t.id!==r.accountId&&(t.currency||w.getPrimaryCurrency())===p}),m.innerHTML=y.map(function(t){return'")}).join(""),v.style.display=y.length?"":"none"),o.style.display="flex",u.style.display="flex",d.style.display="none",h.innerHTML="",t.p=2,t.n=3,this.findTransactionMatches(e);case 3:if(b=t.v,u.style.display="none",b.matches&&0!==b.matches.length){t.n=4;break}return d.style.display="flex",t.a(2);case 4:h.innerHTML=b.matches.map(function(t){var n,a=null===(n=w.accounts)||void 0===n?void 0:n.find(function(e){return e.id===t.accountId}),r=t.accountCurrency||(null==a?void 0:a.currency)||w.getPrimaryCurrency(),o="credit"===t.type?"positive":"negative";return'\n
\n ').concat(w.formatDate(t.date),'\n ').concat(s.ZD(t.description),'\n ').concat(w.formatCurrency(t.amount,r),'\n \n \n
\n ")}).join(""),t.n=6;break;case 5:t.p=5,t.v,u.style.display="none",d.style.display="flex",d.querySelector("p").textContent=(0,i.Tl)("budget","Failed to search for matches. Please try again.");case 6:return t.a(2)}},t,this,[[2,5]])})),function(t){return L.apply(this,arguments)})},{key:"handleLinkMatch",value:(B=Se(Te().m(function t(e,n){var a;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,this.linkTransactions(e,n);case 1:return(0,c.Te)((0,i.Tl)("budget","Transactions linked as transfer")),document.getElementById("matching-modal").style.display="none",t.n=2,this.app.loadTransactions();case 2:t.n=4;break;case 3:t.p=3,a=t.v,(0,c.Qg)(a.message||(0,i.Tl)("budget","Failed to link transactions"));case 4:return t.a(2)}},t,this,[[0,3]])})),function(t,e){return B.apply(this,arguments)})},{key:"handleUnlinkTransaction",value:(D=Se(Te().m(function t(e){var n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.n=1,(0,l.ZD)((0,i.Tl)("budget","Are you sure you want to unlink this transaction from its transfer pair?"));case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,this.unlinkTransaction(e);case 3:return(0,c.Te)((0,i.Tl)("budget","Transaction unlinked")),t.n=4,this.app.loadTransactions();case 4:t.n=6;break;case 5:t.p=5,n=t.v,(0,c.Qg)(n.message||(0,i.Tl)("budget","Failed to unlink transaction"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(t){return D.apply(this,arguments)})},{key:"linkTransactionToBill",value:(M=Se(Te().m(function t(e){var n,a,r=this;return Te().w(function(t){for(;;)switch(t.n){case 0:if(a=null===(n=this.transactions)||void 0===n?void 0:n.find(function(t){return t.id===e})){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Transaction not found")),t.a(2);case 1:return t.n=2,(0,ee.O)("transaction-bill-".concat(e),null,Se(Te().m(function t(){var n,o,s,l,u,d;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/bills",{errorMessage:(0,i.Tl)("budget","Failed to load bills")});case 1:o=t.v,t.n=3;break;case 2:return t.p=2,u=t.v,(0,c.Qg)(u.message),t.a(2);case 3:return t.n=4,se(ie(o,a),r.settings,a);case 4:if(null!==(s=t.v)){t.n=5;break}return t.a(2);case 5:return t.p=5,t.n=6,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/bill"),{method:"POST",body:{billId:s},errorMessage:(0,i.Tl)("budget","Failed to link the transaction to the bill")});case 6:t.n=8;break;case 7:return t.p=7,d=t.v,(0,c.Qg)(d.message),t.a(2);case 8:return l=(o||[]).find(function(t){return t.id===s}),(0,c.Te)((0,i.Tl)("budget","Transaction linked to {bill}",{bill:null!==(n=null==l?void 0:l.name)&&void 0!==n?n:""})),t.n=9,r.app.loadTransactions();case 9:return t.a(2)}},t,null,[[5,7],[0,2]])})));case 2:return t.a(2)}},t,this)})),function(t){return M.apply(this,arguments)})},{key:"unlinkTransactionFromBill",value:(_=Se(Te().m(function t(e){var n,a=this;return Te().w(function(t){for(;;)switch(t.n){case 0:if(null==(n=(this.transactions||[]).find(function(t){return t.id===e}))||!n.billLatestPayment){t.n=2;break}return t.n=1,(0,l.T3)((0,i.Tl)("budget","This is the bill's latest payment. Use Mark Unpaid on the bill to undo it."),{title:(0,i.Tl)("budget","Unlink from bill")});case 1:case 5:return t.a(2);case 2:return t.n=3,(0,l.ZD)((0,i.Tl)("budget","Unlink this transaction from its bill? It stays in the account, but the bill no longer counts it as a payment."),{confirmLabel:(0,i.Tl)("budget","Unlink from bill")});case 3:if(t.v){t.n=4;break}return t.a(2);case 4:return t.n=5,(0,ee.O)("transaction-bill-".concat(e),null,Se(Te().m(function t(){var n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/bill"),{method:"DELETE",errorMessage:(0,i.Tl)("budget","Failed to unlink the transaction from the bill")});case 1:t.n=3;break;case 2:return t.p=2,n=t.v,(0,c.Qg)(n.message),t.a(2);case 3:return(0,c.Te)((0,i.Tl)("budget","Transaction unlinked from its bill")),t.n=4,a.app.loadTransactions();case 4:return t.a(2)}},t,null,[[0,2]])})))}},t,this)})),function(t){return _.apply(this,arguments)})},{key:"showSplitModal",value:(A=Se(Te().m(function t(e){var n,a,r,o,l,u,d,h,g,p,f,m,v=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(r=null===(n=this.transactions)||void 0===n?void 0:n.find(function(t){return t.id===e})){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Transaction not found")),t.a(2);case 1:if(o=document.getElementById("split-modal")){t.n=2;break}return console.error("Split modal not found"),t.a(2);case 2:if(l=r.isSplit||r.is_split,u=document.getElementById("split-modal-title"),d=document.getElementById("split-transaction-info"),h=document.getElementById("splits-container"),u.textContent=l?(0,i.Tl)("budget","Edit Transaction Splits"):(0,i.Tl)("budget","Split Transaction"),o.dataset.transactionId=e,g=null===(a=this.accounts)||void 0===a?void 0:a.find(function(t){return t.id===r.accountId}),p=r.accountCurrency||(null==g?void 0:g.currency)||this.getPrimaryCurrency(),d.innerHTML='\n
\n '.concat((0,i.Tl)("budget","Date:"),"\n ").concat(this.formatDate(r.date),'\n
\n
\n ').concat((0,i.Tl)("budget","Description:"),"\n ").concat(s.ZD(r.description),'\n
\n
\n ').concat((0,i.Tl)("budget","Total Amount:"),'\n ').concat(this.formatCurrency(r.amount,p),"\n
\n "),o.dataset.totalAmount=r.amount,o.dataset.currency=p,h.innerHTML="",!l){t.n=7;break}return t.p=3,t.n=4,this.getTransactionSplits(e);case 4:t.v.forEach(function(t,e){v.addSplitRow(h,t,0===e)}),t.n=6;break;case 5:t.p=5,m=t.v,console.error("Failed to load splits:",m),this.addSplitRow(h,null,!0),this.addSplitRow(h,null,!1);case 6:t.n=8;break;case 7:this.addSplitRow(h,null,!0),this.addSplitRow(h,null,!1);case 8:(f=document.getElementById("split-unsplit-btn"))&&(f.style.display=l?"":"none",f.onclick=function(){return v.unsplitTransaction()}),this.updateSplitRemaining(),o.style.display="flex";case 9:return t.a(2)}},t,this,[[3,5]])})),function(t){return A.apply(this,arguments)})},{key:"addSplitRow",value:function(t){var e,n=this,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],o=document.getElementById("split-modal"),c=t.children.length,l=parseInt(null==o?void 0:o.dataset.transactionId),u=null===(e=this.transactions)||void 0===e?void 0:e.find(function(t){return t.id===l}),d=(null==u?void 0:u.type)||"debit",h=document.createElement("div");h.className="split-row",h.dataset.index=c,h.innerHTML='\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n '),h.querySelector(".split-amount").addEventListener("input",function(){return n.updateSplitRemaining()}),h.querySelector(".split-remove-btn").addEventListener("click",function(t){t.currentTarget.classList.contains("disabled")||(h.remove(),n.updateSplitRemaining())}),t.appendChild(h)}},{key:"getCategoryOptions",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!this.categories)return"";var n="credit"===e?"income":"expense";return this.categories.filter(function(t){return t.type===n}).map(function(e){return'")}).join("")}},{key:"updateSplitRemaining",value:function(){var t=document.getElementById("split-modal"),e=parseFloat((null==t?void 0:t.dataset.totalAmount)||0),n=(null==t?void 0:t.dataset.currency)||this.getPrimaryCurrency(),a=document.getElementById("split-remaining"),r=document.getElementById("split-remaining-amount"),i=e-Array.from(document.querySelectorAll(".split-amount")).reduce(function(t,e){return t+(parseFloat(e.value)||0)},0);a&&r&&(r.textContent=this.formatCurrency(Math.abs(i),n),a.classList.toggle("over",i<-.01),a.classList.toggle("balanced",Math.abs(i)<.01))}},{key:"getTransactionSplits",value:(I=Se(Te().m(function t(e){return Te().w(function(t){for(;;)switch(t.n){case 0:return t.n=1,(0,T.n)("/apps/budget/api/transactions/".concat(e,"/splits"));case 1:return t.a(2,t.v)}},t)})),function(t){return I.apply(this,arguments)})},{key:"saveSplits",value:(C=Se(Te().m(function t(){var e,n,a,r,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.getElementById("split-modal"),n=parseInt(null==e?void 0:e.dataset.transactionId),a=parseFloat((null==e?void 0:e.dataset.totalAmount)||0),!((r=Array.from(document.querySelectorAll(".split-row")).map(function(t){return{amount:parseFloat(t.querySelector(".split-amount").value)||0,categoryId:parseInt(t.querySelector(".split-category").value)||null,description:t.querySelector(".split-description").value.trim()||null}}).filter(function(t){return t.amount>0})).length<2)){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","A split transaction must have at least 2 parts")),t.a(2);case 1:if(o=r.reduce(function(t,e){return t+e.amount},0),!(Math.abs(o-a)>.01)){t.n=2;break}return(0,c.I9)((0,i.Tl)("budget","Split amounts ({splitTotal}) must equal transaction amount ({totalAmount})",{splitTotal:o.toFixed(2),totalAmount:a.toFixed(2)})),t.a(2);case 2:return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/transactions/".concat(n,"/splits"),{method:"POST",body:{splits:r}});case 3:return this.hideSplitModal(),(0,c.Te)((0,i.Tl)("budget","Transaction split successfully")),t.n=4,this.app.loadTransactions();case 4:t.n=6;break;case 5:t.p=5,s=t.v,console.error("Failed to save splits:",s),(0,c.Qg)(s.message||(0,i.Tl)("budget","Failed to save splits"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return C.apply(this,arguments)})},{key:"unsplitTransaction",value:(S=Se(Te().m(function t(){var e,n,a;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return e=document.getElementById("split-modal"),n=parseInt(null==e?void 0:e.dataset.transactionId),t.n=1,(0,l.ZD)((0,i.Tl)("budget","Are you sure you want to remove the split and revert to a single transaction?"));case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/transactions/".concat(n,"/splits"),{method:"DELETE"});case 3:return this.hideSplitModal(),(0,c.Te)((0,i.Tl)("budget","Transaction unsplit successfully")),t.n=4,this.app.loadTransactions();case 4:t.n=6;break;case 5:t.p=5,a=t.v,console.error("Failed to unsplit transaction:",a),(0,c.Qg)(a.message||(0,i.Tl)("budget","Failed to unsplit transaction"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return S.apply(this,arguments)})},{key:"hideSplitModal",value:function(){var t=document.getElementById("split-modal");t&&(t.style.display="none")}},{key:"scanForMatches",value:(x=Se(Te().m(function t(){var e,n=arguments;return Te().w(function(t){for(;;)switch(t.n){case 0:return e=n.length>0&&void 0!==n[0]?n[0]:3,t.n=1,(0,T.n)("/apps/budget/api/transactions/scan-matches?dateWindow=".concat(e));case 1:return t.a(2,t.v)}},t)})),function(){return x.apply(this,arguments)})},{key:"bulkLinkPairs",value:(E=Se(Te().m(function t(e){return Te().w(function(t){for(;;)switch(t.n){case 0:return t.n=1,(0,T.n)("/apps/budget/api/transactions/bulk-link",{method:"POST",body:{pairs:e}});case 1:return t.a(2,t.v)}},t)})),function(t){return E.apply(this,arguments)})},{key:"showBulkMatchModal",value:function(){var t=document.getElementById("bulk-match-modal"),e=document.getElementById("bulk-match-config"),n=document.getElementById("bulk-match-loading"),a=document.getElementById("bulk-match-results"),r=document.getElementById("bulk-match-empty"),o=document.getElementById("confirm-selected-btn");e.style.display="block",n.style.display="none",a.style.display="none",r.style.display="none",o&&(o.style.display="none"),document.getElementById("auto-matched-section").style.display="none",document.getElementById("needs-review-section").style.display="none",document.getElementById("auto-matched-list").innerHTML="",document.getElementById("needs-review-list").innerHTML="",e.innerHTML='\n
\n \n
\n \n 3\n
\n

').concat((0,i.Tl)("budget","Matches must be within this many days of each other. Use 0 for exact date match."),'

\n
\n
\n \n
\n \n \n
\n
\n ");var s=document.getElementById("match-date-window"),c=document.getElementById("match-date-window-value");s.addEventListener("input",function(){c.textContent=s.value}),this._bulkMatchDirty=!1,t.style.display="flex"}},{key:"startScan",value:(y=Se(Te().m(function t(){var e,n,a,r,o,s,c,l,u,d,h,g;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return n=document.getElementById("bulk-match-config"),a=document.getElementById("bulk-match-loading"),r=parseInt(document.getElementById("match-date-window").value)||3,o=(null===(e=document.querySelector('input[name="match-mode"]:checked'))||void 0===e?void 0:e.value)||"auto",n.style.display="none",(s=document.getElementById("start-scan-btn"))&&(s.style.display="none"),a.style.display="flex",a.querySelector("p").textContent=(0,i.Tl)("budget","Scanning for matching transactions..."),t.p=1,t.n=2,this.scanForMatches(r);case 2:if(c=t.v,a.style.display="none",0!==c.stats.totalCandidates){t.n=3;break}return l=document.getElementById("bulk-match-results"),u=document.getElementById("bulk-match-empty"),l.style.display="block",u.style.display="flex",u.querySelector("p").textContent=(0,i.Tl)("budget","No matching transactions found."),t.a(2);case 3:if("auto"!==o){t.n=5;break}return t.n=4,this.handleAutoMode(c);case 4:t.n=6;break;case 5:this.handleReviewMode(c);case 6:t.n=8;break;case 7:t.p=7,g=t.v,a.style.display="none",d=document.getElementById("bulk-match-results"),h=document.getElementById("bulk-match-empty"),d.style.display="block",h.style.display="flex",h.querySelector("p").textContent=g.message||(0,i.Tl)("budget","Failed to scan for matches. Please try again.");case 8:return t.a(2)}},t,this,[[1,7]])})),function(){return y.apply(this,arguments)})},{key:"handleAutoMode",value:(v=Se(Te().m(function t(e){var n,a,r,o,s,c,l,u,d,h,g,p=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.getElementById("bulk-match-loading"),a=document.getElementById("bulk-match-results"),r=document.getElementById("auto-matched-section"),o=document.getElementById("needs-review-section"),s=document.getElementById("auto-matched-list"),c=document.getElementById("needs-review-list"),l=e.candidates.filter(function(t){return 1===t.matchCount}),u=e.candidates.filter(function(t){return t.matchCount>1}),d=0,!(l.length>0)){t.n=5;break}return n.style.display="flex",n.querySelector("p").textContent=(0,i.zw)("budget","Linking %n exact match pair...","Linking %n exact match pairs...",l.length),h=l.map(function(t){return{sourceId:parseInt(t.transaction.id),targetId:parseInt(t.matches[0].id)}}),t.p=1,t.n=2,this.bulkLinkPairs(h);case 2:g=t.v,d=g.stats.linkedCount,this._bulkMatchDirty=!0,t.n=4;break;case 3:return t.p=3,t.v,n.style.display="none",this.handleReviewMode(e),t.a(2);case 4:n.style.display="none";case 5:a.style.display="block",document.getElementById("auto-matched-count").textContent=d,document.getElementById("needs-review-count").textContent=u.length,d>0&&(r.style.display="block",s.innerHTML=l.map(function(t){return p.renderAutoMatchedPair({transaction:t.transaction,linkedTo:t.matches[0]})}).join("")),u.length>0&&(o.style.display="block",c.innerHTML=u.map(function(t,e){return p.renderNeedsReviewItem(t,e)}).join("")),0===d&&0===u.length&&(document.getElementById("bulk-match-empty").style.display="flex");case 6:return t.a(2)}},t,this,[[1,3]])})),function(t){return v.apply(this,arguments)})},{key:"handleReviewMode",value:function(t){var e=this,n=document.getElementById("bulk-match-results"),a=document.getElementById("auto-matched-section"),r=document.getElementById("needs-review-section"),o=document.getElementById("auto-matched-list"),s=document.getElementById("needs-review-list"),c=document.getElementById("confirm-selected-btn");n.style.display="block";var l=t.candidates.filter(function(t){return 1===t.matchCount}),u=t.candidates.filter(function(t){return t.matchCount>1});document.getElementById("auto-matched-count").textContent=l.length,document.getElementById("needs-review-count").textContent=u.length,l.length>0&&(a.style.display="block",a.querySelector("h4").textContent=(0,i.Tl)("budget","Exact Matches"),a.querySelector(".section-hint").textContent=(0,i.Tl)("budget","These transactions have exactly one match. Uncheck any you don't want to link."),o.innerHTML=l.map(function(t,n){return e.renderReviewSingleMatch(t,n)}).join("")),u.length>0&&(r.style.display="block",s.innerHTML=u.map(function(t,n){return e.renderNeedsReviewItem(t,n)}).join("")),c&&(c.style.display="inline-block")}},{key:"renderAutoMatchedPair",value:function(t){var e=t.transaction,n=t.linkedTo,a=e.account_currency||this.getPrimaryCurrency(),r=n.accountCurrency||this.getPrimaryCurrency(),o="credit"===e.type?"positive":"negative",c="credit"===n.type?"positive":"negative";return'\n
\n
\n ').concat(this.formatDate(e.date),'\n ').concat(s.ZD(e.description),'\n
\n ').concat(this.formatCurrency(e.amount,a),'\n \n
\n
\n ↔\n
\n ').concat(this.formatDate(n.date),'\n ').concat(s.ZD(n.description),'\n
\n ').concat(this.formatCurrency(n.amount,r),'\n \n
\n
\n \n
\n ")}},{key:"renderReviewSingleMatch",value:function(t,e){var n=t.transaction,a=t.matches[0],r=n.account_currency||this.getPrimaryCurrency(),i=a.accountCurrency||this.getPrimaryCurrency(),o="credit"===n.type?"positive":"negative",c="credit"===a.type?"positive":"negative";return'\n
\n \n
\n
\n ').concat(this.formatDate(n.date),'\n ').concat(s.ZD(n.description),'\n
\n ').concat(this.formatCurrency(n.amount,r),'\n \n
\n
\n ↔\n
\n ').concat(this.formatDate(a.date),'\n ').concat(s.ZD(a.description),'\n
\n ').concat(this.formatCurrency(a.amount,i),'\n \n
\n
\n
\n
\n ")}},{key:"renderNeedsReviewItem",value:function(t,e){var n=this,a=t.transaction,r=a.account_currency||this.getPrimaryCurrency(),o="credit"===a.type?"positive":"negative",c=t.matches.map(function(t){var a=t.accountCurrency||n.getPrimaryCurrency(),r="credit"===t.type?"positive":"negative";return'\n \n ")}).join("");return'\n
\n
\n
\n ').concat(this.formatDate(a.date),'\n ').concat(s.ZD(a.description),'\n
\n ').concat(this.formatCurrency(a.amount,r),'\n \n
\n
\n
\n
').concat((0,i.zw)("budget","Select a match (%n option):","Select a match (%n options):",t.matchCount),'
\n
\n ').concat(c,'\n
\n \n
\n ")}},{key:"handleConfirmSelected",value:(m=Se(Te().m(function t(){var e,n,a,r,o,s,l,u,d;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=[],document.querySelectorAll(".review-single-check:checked").forEach(function(t){e.push({sourceId:parseInt(t.dataset.sourceId),targetId:parseInt(t.dataset.targetId)})}),document.querySelectorAll(".bulk-review-item").forEach(function(t){var n=t.querySelector('input[type="radio"]:checked');n&&e.push({sourceId:parseInt(t.dataset.txId),targetId:parseInt(n.value)})}),0!==e.length){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","No matches selected")),t.a(2);case 1:return(n=document.getElementById("confirm-selected-btn"))&&(n.disabled=!0,n.textContent=(0,i.Tl)("budget","Linking...")),t.p=2,t.n=3,this.bulkLinkPairs(e);case 3:a=t.v,this._bulkMatchDirty=!0,r=(0,i.zw)("budget","Linked %n pair","Linked %n pairs",a.stats.linkedCount),a.stats.failedCount>0&&(r+=", "+(0,i.zw)("budget","%n failed","%n failed",a.stats.failedCount)),(0,c.Te)(r),o=document.getElementById("auto-matched-section"),s=document.getElementById("auto-matched-list"),l=document.getElementById("needs-review-section"),a.stats.linkedCount>0&&(o.style.display="block",o.querySelector("h4").textContent=(0,i.Tl)("budget","Linked Pairs"),o.querySelector(".section-hint").textContent=(0,i.Tl)("budget","These transactions have been linked. Click Undo to unlink a pair."),u=[],document.querySelectorAll(".review-single-match").forEach(function(t){var e=t.dataset.sourceId,n=t.dataset.targetId;if(a.linked.some(function(t){return t.sourceId==e&&t.targetId==n})){var r=t.querySelector(".pair-content");r&&u.push('\n
\n ').concat(r.innerHTML,'\n \n
\n "))}}),s.innerHTML=u.join(""),document.getElementById("auto-matched-count").textContent=a.stats.linkedCount),l.style.display="none",n&&(n.style.display="none"),document.getElementById("needs-review-count").textContent="0",t.n=5;break;case 4:t.p=4,d=t.v,(0,c.Qg)(d.message||(0,i.Tl)("budget","Failed to link transactions"));case 5:return t.p=5,n&&(n.disabled=!1,n.textContent=(0,i.Tl)("budget","Confirm Selected")),t.f(5);case 6:return t.a(2)}},t,this,[[2,4,5,6]])})),function(){return m.apply(this,arguments)})},{key:"handleBulkMatchUndo",value:(f=Se(Te().m(function t(e){var n,a,r,o;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,this.unlinkTransaction(e);case 1:this._bulkMatchDirty=!0,(n=document.querySelector('.bulk-match-pair[data-tx-id="'.concat(e,'"]')))&&n.remove(),a=document.getElementById("auto-matched-count"),r=parseInt(a.textContent),a.textContent=r-1,0===document.getElementById("auto-matched-list").children.length&&(document.getElementById("auto-matched-section").style.display="none"),(0,c.Te)((0,i.Tl)("budget","Match undone")),t.n=3;break;case 2:t.p=2,o=t.v,(0,c.Qg)(o.message||(0,i.Tl)("budget","Failed to undo match"));case 3:return t.a(2)}},t,this,[[0,2]])})),function(t){return f.apply(this,arguments)})},{key:"handleBulkMatchLink",value:(p=Se(Te().m(function t(e,n){var a,r,o,s,l,u,d,h;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(a=document.querySelector('.bulk-review-item[data-index="'.concat(n,'"]')),r=a.querySelector('input[name="review-match-'.concat(n,'"]:checked'))){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please select a match first")),t.a(2);case 1:return o=parseInt(r.value),t.p=2,t.n=3,this.linkTransactions(e,o);case 3:this._bulkMatchDirty=!0,a.remove(),s=document.getElementById("needs-review-count"),l=document.getElementById("auto-matched-count"),u=parseInt(s.textContent),d=parseInt(l.textContent),s.textContent=u-1,l.textContent=d+1,0===document.getElementById("needs-review-list").children.length&&(document.getElementById("needs-review-section").style.display="none"),(0,c.Te)((0,i.Tl)("budget","Transactions linked")),t.n=5;break;case 4:t.p=4,h=t.v,(0,c.Qg)(h.message||(0,i.Tl)("budget","Failed to link transactions"));case 5:return t.a(2)}},t,this,[[2,4]])})),function(t,e){return p.apply(this,arguments)})},{key:"setupInlineEditingListeners",value:function(){var t=this,e=document.getElementById("transactions-table");e&&(e.addEventListener("click",function(e){if(window.matchMedia(Le).matches){var n=e.target.closest("tr.transaction-row");n&&!e.target.closest("input, button, a, select, .linked-indicator, .cell-editing, .editing")&&(e.preventDefault(),e.stopPropagation(),n.dataset.readOnly||t.editTransaction(parseInt(n.dataset.transactionId,10)))}},!0),e.addEventListener("click",function(e){var n=e.target.closest(".editable-cell");if(n&&!n.classList.contains("editing")){if("checkbox"===e.target.type)return;if(e.target.closest(".linked-indicator"))return;t.startInlineEdit(n)}}),document.addEventListener("click",function(e){e.target.closest(".editable-cell")||e.target.closest(".category-autocomplete-dropdown")||t.closeAllInlineEditors()}))}},{key:"startInlineEdit",value:function(t){this.closeAllInlineEditors();var e=t.dataset.field,n=t.dataset.value,a=parseInt(t.dataset.transactionId),r=this.transactions.find(function(t){return t.id===a});if(r)switch(t.classList.add("editing"),t.removeAttribute("title"),this.currentEditingCell=t,this.originalValue=n,e){case"date":this.createDateEditor(t,n);break;case"description":this.createTextEditor(t,n,"description");break;case"categoryId":this.createCategoryEditor(t,n,r);break;case"amount":this.createAmountEditor(t,r);break;case"accountId":this.createAccountEditor(t,n);break;case"tags":this.createTagsEditor(t,r);break;default:this.createTextEditor(t,n,e)}}},{key:"createDateEditor",value:function(t,e){var n,a=this,r=document.createElement("input");r.type="text",r.className="inline-edit-input",t.innerHTML="",t.appendChild(r);var i=(null===(n=this.app.settings)||void 0===n?void 0:n.date_format)||"Y-m-d",o=(0,ge.A)(r,{dateFormat:i,defaultDate:e,allowInput:!0,disableMobile:!0}),s=function(){return o.selectedDates.length>0?o.formatDate(o.selectedDates[0],"Y-m-d"):e};r.addEventListener("keydown",function(e){if("Escape"===e.key)o.destroy(),a.cancelInlineEdit(t);else if("Enter"===e.key){e.preventDefault();var n=s();o.destroy(),a.saveInlineEdit(t,"date",n)}}),r.addEventListener("blur",function(){setTimeout(function(){if(t.classList.contains("editing")&&!o.isOpen){var e=s();o.destroy(),a.saveInlineEdit(t,"date",e)}},200)}),r.focus()}},{key:"createTextEditor",value:function(t,e,n){var a=document.createElement("input");a.type="text",a.className="inline-edit-input",a.value=e||"",a.placeholder="description"===n?(0,i.Tl)("budget","Enter description..."):"",this.setupEditorEvents(a,t,n),t.innerHTML="",t.appendChild(a),a.focus(),a.select()}},{key:"createAmountEditor",value:function(t,e){var n=(0,pe.XV)(document.createElement("input"));n.className="inline-edit-input",n.value="debit"===e.type?-Math.abs(e.amount):Math.abs(e.amount),n.dataset.type=e.type,this.setupEditorEvents(n,t,"amount"),t.innerHTML="",t.appendChild(n),n.focus(),n.select()}},{key:"createCategoryEditor",value:function(t,e){var n=this,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=document.createElement("div");r.className="category-autocomplete";var o=document.createElement("input");o.type="text",o.className="category-autocomplete-input",o.placeholder=(0,i.Tl)("budget","Type to search...");var c=a?(this.accounts||[]).find(function(t){return t.id===a.accountId}):null,l=(0,k.hM)(this.categories,[c],[e]),u=null;l?u=(0,k.QN)(l):this.categoryTree&&this.categoryTree.length>0?u=this.categoryTree:this.allCategories&&this.allCategories.length>0?u=this.allCategories:this.categories&&this.categories.length>0&&(u=this.categories);var d=u?this.getFlatCategoryList(u):[],h=d.find(function(t){return t.id===parseInt(e)});o.value=h?h.name:e?(null==a?void 0:a.categoryName)||(0,w.pC)(null):"",o.dataset.categoryId=e||"";var g=document.createElement("div");g.className="category-autocomplete-dropdown",g.style.display="none",r.appendChild(o),r.appendChild(g);var p=ue(g,r,{onHidden:function(){return v(function(){return n.cancelInlineEdit(t)})}}),f=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=t?d.filter(function(e){return e.name.toLowerCase().includes(t.toLowerCase())}):d;0===e.length?g.innerHTML='
'.concat((0,i.Tl)("budget","No categories found"),"
"):g.innerHTML=e.map(function(t){return'\n
\n ').concat(s.ZD(t.prefix)).concat(s.ZD(t.name),"\n
\n ")}).join(""),g.innerHTML='\n
\n ').concat((0,i.Tl)("budget","Uncategorized"),"\n
\n ")+g.innerHTML,g.style.display="block",p()};o.addEventListener("focus",function(){return f(o.value)}),o.addEventListener("input",function(){return f(o.value)});var m=!1,v=function(t){m||(m=!0,g.style.display="none",t())};g.addEventListener("mousedown",function(e){e.preventDefault(),e.stopPropagation();var a=e.target.closest(".category-autocomplete-item");a&&(o.dataset.categoryId=a.dataset.categoryId,o.value=a.dataset.categoryName,v(function(){return n.saveInlineEdit(t,"categoryId",a.dataset.categoryId)}))}),g.addEventListener("click",function(t){t.stopPropagation()}),o.addEventListener("keydown",function(e){"Escape"===e.key?v(function(){return n.cancelInlineEdit(t)}):"Enter"===e.key?(e.preventDefault(),v(function(){return n.saveInlineEdit(t,"categoryId",o.dataset.categoryId)})):"ArrowDown"!==e.key&&"ArrowUp"!==e.key||(e.preventDefault(),n.navigateCategoryDropdown(g,"ArrowDown"===e.key?1:-1,o))}),o.addEventListener("blur",function(){setTimeout(function(){r.contains(document.activeElement)||v(function(){o.dataset.categoryId!==(e||"")?n.saveInlineEdit(t,"categoryId",o.dataset.categoryId):n.cancelInlineEdit(t)})},200)}),t.innerHTML="",t.appendChild(r),o.focus(),o.select(),f()}},{key:"navigateCategoryDropdown",value:function(t,e,n){var a=t.querySelectorAll(".category-autocomplete-item");if(0!==a.length){var r=t.querySelector(".category-autocomplete-item.highlighted"),i=0;r?(r.classList.remove("highlighted"),(i=Array.from(a).indexOf(r)+e)<0&&(i=a.length-1),i>=a.length&&(i=0)):i=1===e?0:a.length-1,a[i].classList.add("highlighted"),a[i].scrollIntoView({block:"nearest"}),n.dataset.categoryId=a[i].dataset.categoryId}}},{key:"createAccountEditor",value:function(t,e){var n=this,a=document.createElement("select");a.className="inline-edit-select",(0,k.ig)(this.accounts,e).forEach(function(t){var n=document.createElement("option");n.value=t.id,n.textContent=(0,k.Jo)(t),n.selected=t.id===parseInt(e),a.appendChild(n)}),a.addEventListener("keydown",function(e){"Escape"===e.key?n.cancelInlineEdit(t):"Enter"===e.key&&(e.preventDefault(),n.saveInlineEdit(t,"accountId",a.value))}),a.addEventListener("change",function(){n.saveInlineEdit(t,"accountId",a.value)}),a.addEventListener("blur",function(){setTimeout(function(){t.classList.contains("editing")&&n.cancelInlineEdit(t)},100)}),t.innerHTML="",t.appendChild(a),a.focus()}},{key:"createTagsEditor",value:(h=Se(Te().m(function t(e,n){var a,r,o,c,l,u,d,h,g,p,f,m,v,y,b,w,k,E,x,S,C,I,A,_,M,D,B,L=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return a=n.categoryId,e.innerHTML=''.concat((0,i.Tl)("budget","Loading..."),""),t.p=1,o=null===(r=this.accounts)||void 0===r?void 0:r.find(function(t){return t.id===n.accountId}),c=!(null==o||!o._shared),t.n=2,Promise.all([c?Promise.resolve([]):(0,T.n)("/apps/budget/api/tags/global").catch(function(){return[]}),a?this.loadTagSetsForCategory(a):Promise.resolve([])]);case 2:if(l=t.v,u=Ee(l,2),d=u[0],h=u[1],0!==(g=d||[]).length||0!==h.length){t.n=3;break}return e.innerHTML=''.concat((0,i.Tl)("budget","No tags"),""),setTimeout(function(){return L.cancelInlineEdit(e)},1500),t.a(2);case 3:p=this.app.getTransactionTagIds(n.id),f=new Set(p),m=new Set(p),v=null,y=!1,(b=document.createElement("div")).className="tags-autocomplete",(w=document.createElement("input")).type="text",w.className="tags-autocomplete-input",w.placeholder=(0,i.Tl)("budget","Type to filter tags..."),(k=document.createElement("div")).className="tags-autocomplete-dropdown",k.style.display="none",b.appendChild(w),b.appendChild(k),E=ue(k,b,{onHidden:function(){return D(!1)}}),x=[],g.length>0&&g.forEach(function(t){x.push({id:t.id,name:t.name,color:t.color,tagSetName:(0,i.Tl)("budget","Tags"),tagSetId:"global"})}),h.forEach(function(t){t.tags.forEach(function(e){x.push({id:e.id,name:e.name,color:e.color,tagSetName:t.name,tagSetId:t.id})})}),S=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=t?x.filter(function(e){return e.name.toLowerCase().includes(t.toLowerCase())||e.tagSetName.toLowerCase().includes(t.toLowerCase())}):x,n={};e.forEach(function(t){n[t.tagSetId]||(n[t.tagSetId]={name:t.tagSetName,tags:[]}),n[t.tagSetId].tags.push(t)});var a="";Object.values(n).forEach(function(t){a+='
'.concat(s.ZD(t.name),"
"),t.tags.forEach(function(t){var e=f.has(t.id),n=t.id===v;a+='\n
\n \n ').concat(s.ZD(t.name),'\n \n ').concat(e?"✓":"","\n
\n ")})}),k.innerHTML=a||'
'.concat((0,i.Tl)("budget","No tags found"),"
"),k.style.display="block",E()},w.addEventListener("focus",function(){return S(w.value)}),w.addEventListener("input",function(){return S(w.value)}),C=function(t){var e=x.find(function(e){return e.id===t});e&&("global"!==e.tagSetId&&x.filter(function(t){return t.tagSetId===e.tagSetId}).forEach(function(e){e.id!==t&&f.delete(e.id)}),f.has(t)?f.delete(t):f.add(t),t===v&&(y=!0))},I=function(){return null===v?null:k.querySelector('.tags-autocomplete-item[data-tag-id="'.concat(v,'"]'))},A=function(t){var e=ve(k.querySelectorAll(".tags-autocomplete-item"));if(0!==e.length){var n=e.indexOf(I()),a=n<0?1===t?0:e.length-1:(n+t+e.length)%e.length;e.forEach(function(t){return t.classList.remove("highlighted")}),e[a].classList.add("highlighted"),e[a].scrollIntoView({block:"nearest"}),v=parseInt(e[a].dataset.tagId,10),y=!1}},_=function(){return f.size===m.size&&ve(f).every(function(t){return m.has(t)})},M=!1,D=function(t){M||(M=!0,k.style.display="none",t&&!_()?L.saveTagsFromEditor(e,f,n.id):L.cancelInlineEdit(e))},k.addEventListener("mousedown",function(t){t.preventDefault(),t.stopPropagation();var e=t.target.closest(".tags-autocomplete-item");e&&(C(parseInt(e.dataset.tagId,10)),S(w.value))}),k.addEventListener("click",function(t){t.stopPropagation()}),w.addEventListener("keydown",function(t){"Escape"===t.key?D(!1):"Enter"===t.key?(t.preventDefault(),!I()||y||f.has(v)||C(v),D(!0)):"ArrowDown"===t.key||"ArrowUp"===t.key?(t.preventDefault(),A("ArrowDown"===t.key?1:-1)):" "===t.key&&I()&&(t.preventDefault(),C(v),S(w.value))}),w.addEventListener("blur",function(){setTimeout(function(){return D(!0)},200)}),e.innerHTML="",e.appendChild(b),w.focus(),S(),t.n=5;break;case 4:t.p=4,B=t.v,console.error("Failed to load tag sets:",B),e.innerHTML=''.concat((0,i.Tl)("budget","Error loading tags"),""),setTimeout(function(){return L.cancelInlineEdit(e)},1500);case 5:return t.a(2)}},t,this,[[1,4]])})),function(t,e){return h.apply(this,arguments)})},{key:"saveTagsFromEditor",value:(d=Se(Te().m(function t(e,n,a){var r,o,s;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return r=Array.from(n),t.p=1,t.n=2,(0,T.n)("/apps/budget/api/transactions/".concat(a,"/tags"),{method:"PUT",body:{tagIds:r},errorMessage:(0,i.Tl)("budget","Failed to update tags")});case 2:return t.n=3,this.app.loadTransactionTags(a);case 3:this.cancelInlineEdit(e),(o=e.querySelector(".cell-display"))&&(o.innerHTML=this.app.renderTransactionTags(a)),t.n=5;break;case 4:t.p=4,s=t.v,console.error("Failed to save tags:",s),(0,c.Qg)(s.message||(0,i.Tl)("budget","Failed to update tags")),this.cancelInlineEdit(e);case 5:return t.a(2)}},t,this,[[1,4]])})),function(t,e,n){return d.apply(this,arguments)})},{key:"loadTagSetsForCategory",value:(r=Se(Te().m(function t(e){var n;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)("/apps/budget/api/tag-sets?categoryId=".concat(e));case 1:return t.a(2,t.v);case 2:return t.p=2,n=t.v,console.error("Failed to load tag sets:",n),t.a(2,[])}},t,null,[[0,2]])})),function(t){return r.apply(this,arguments)})},{key:"setupEditorEvents",value:function(t,e,n){var a=this;t.addEventListener("keydown",function(r){if("Escape"===r.key)a.cancelInlineEdit(e);else if("Enter"===r.key)if(r.preventDefault(),"amount"===n){var i=parseFloat(t.value)||0,o=i<0?"debit":"credit";a.saveInlineEdit(e,n,Math.abs(i).toString(),{type:o})}else a.saveInlineEdit(e,n,t.value)}),t.addEventListener("blur",function(r){setTimeout(function(){if(e.isConnected&&e.classList.contains("editing"))if("amount"===n){var r=parseFloat(t.value)||0,i=r<0?"debit":"credit";a.saveInlineEdit(e,n,Math.abs(r).toString(),{type:i})}else a.saveInlineEdit(e,n,t.value)},100)})}},{key:"saveInlineEdit",value:(a=Se(Te().m(function t(e,n,a){var r,i=arguments;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(r=i.length>3&&void 0!==i[3]?i[3]:{},"true"!==e.dataset.inlineSaving){t.n=1;break}return t.a(2);case 1:return e.dataset.inlineSaving="true",t.p=2,t.n=3,this._saveInlineEdit(e,n,a,r);case 3:return t.a(2,t.v);case 4:return t.p=4,delete e.dataset.inlineSaving,t.f(4);case 5:return t.a(2)}},t,this,[[2,,4,5]])})),function(t,e,n){return a.apply(this,arguments)})},{key:"_saveInlineEdit",value:(n=Se(Te().m(function t(e,n,a){var r,o,s,u,d,h,g,p,f,m,v=arguments;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(r=v.length>3&&void 0!==v[3]?v[3]:{},o=parseInt(e.dataset.transactionId),s=this.transactions.find(function(t){return t.id===o})){t.n=1;break}return this.cancelInlineEdit(e),t.a(2);case 1:if(!s.reconciled||!["amount","date","accountId"].includes(n)){t.n=3;break}return t.n=2,(0,l.ZD)((0,i.Tl)("budget","This transaction was reconciled against a bank statement. Changing its amount, type, account or date will make past reconciliations no longer match. Continue?"));case 2:if(t.v){t.n=3;break}return this.cancelInlineEdit(e),t.a(2);case 3:if(u=!1,"amount"===n?(d=parseFloat(a),h=r.type||s.type,u=d!==s.amount||h!==s.type):"categoryId"===n?(g=""===a?null:parseInt(a),u=g!==s.categoryId):u="accountId"===n?parseInt(a)!==s.accountId:a!==(s[n]||""),u){t.n=4;break}return this.cancelInlineEdit(e),t.a(2);case 4:return e.classList.add("cell-saving"),p={},"amount"===n?(p.amount=parseFloat(a),r.type&&(p.type=r.type)):"categoryId"===n?p.categoryId=""===a?null:parseInt(a):"accountId"===n?p.accountId=parseInt(a):p[n]=a,t.p=5,t.n=6,(0,T.n)("/apps/budget/api/transactions/".concat(o),{method:"PUT",body:p,errorMessage:(0,i.Tl)("budget","Failed to update transaction")});case 6:if(f=t.v,Object.assign(s,f),"accountId"!==n){t.n=7;break}return t.n=7,this.app.loadAccounts();case 7:this.app.renderEnhancedTransactionsTable(),this.app.applyColumnVisibility(),(0,c.Te)((0,i.Tl)("budget","Transaction updated")),t.n=9;break;case 8:t.p=8,m=t.v,console.error("Failed to save inline edit:",m),(0,c.Qg)(m.message||(0,i.Tl)("budget","Failed to update transaction")),this.cancelInlineEdit(e);case 9:return t.a(2)}},t,this,[[5,8]])})),function(t,e,a){return n.apply(this,arguments)})},{key:"cancelInlineEdit",value:function(t){t&&t.classList.contains("editing")&&(this.app.renderEnhancedTransactionsTable(),this.app.applyColumnVisibility(),this.currentEditingCell=null,this.originalValue=null)}},{key:"closeAllInlineEditors",value:function(){var t=this;document.querySelectorAll(".editable-cell.editing").forEach(function(e){t.cancelInlineEdit(e)})}},{key:"getFlatCategoryList",value:function(){var t,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=[],a=me((arguments.length>0&&void 0!==arguments[0]?arguments[0]:null)||this.categories||[]);try{for(a.s();!(t=a.n()).done;){var r=t.value;n.push({id:r.id,name:r.name,prefix:e}),r.children&&r.children.length>0&&(n=n.concat(this.getFlatCategoryList(r.children,e+" ")))}}catch(t){a.e(t)}finally{a.f()}return n}},{key:"showDuplicatesModal",value:(e=Se(Te().m(function t(){var e,n,a,r,o,s,c=this;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:return(e=document.getElementById("duplicates-modal"))&&e.remove(),(n=document.createElement("div")).id="duplicates-modal",n.className="budget-modal-overlay",n.innerHTML='\n
\n
\n

'.concat((0,i.Tl)("budget","Find Duplicate Transactions"),'

\n \n
\n
\n
\n \n

').concat((0,i.Tl)("budget","Scanning for duplicates..."),'

\n
\n \n
\n
\n '),document.body.appendChild(n),n.querySelector(".close-btn").addEventListener("click",function(){n.remove(),c._duplicatesDirty&&(c.app.loadTransactions(),c.app.loadAccounts())}),n.addEventListener("click",function(t){t.target===n&&(n.remove(),c._duplicatesDirty&&(c.app.loadTransactions(),c.app.loadAccounts()))}),this._duplicatesDirty=!1,t.p=1,t.n=2,(0,T.n)("/apps/budget/api/transactions/duplicates");case 2:if(a=t.v,document.getElementById("duplicates-loading").style.display="none",(r=document.getElementById("duplicates-content")).style.display="block",a.groups&&0!==a.groups.length){t.n=3;break}return r.innerHTML='

'.concat((0,i.Tl)("budget","No duplicate transactions found."),"

"),t.a(2);case 3:this.renderDuplicateGroups(r,a.groups),t.n=5;break;case 4:t.p=4,s=t.v,console.error("Failed to find duplicates:",s),document.getElementById("duplicates-loading").style.display="none",(o=document.getElementById("duplicates-content")).style.display="block",o.innerHTML='

'.concat((0,i.Tl)("budget","Failed to scan for duplicates. Please try again."),"

");case 5:return t.a(2)}},t,this,[[1,4]])})),function(){return e.apply(this,arguments)})},{key:"renderDuplicateGroups",value:function(t,e){var n=this,a=e.reduce(function(t,e){return t+e.length-1},0),r='\n
\n

'.concat((0,i.Tl)("budget","Found {groupCount} group(s) with {duplicateCount} suspected duplicate(s). The oldest transaction in each group is kept by default. Review and adjust the selection, then delete the checked items.",{groupCount:e.length,duplicateCount:a}),'

\n
\n \n \n
\n
\n
\n ');e.forEach(function(t,e){var a=t[0],c=o.vv(a.amount,a.currency,n.settings);r+='\n
\n
\n '.concat(s.ZD(a.description)||(0,i.Tl)("budget","(no description)"),"\n — ").concat(c," (").concat(s.ZD(a.type),")\n — ").concat(s.ZD(a.accountName),'\n
\n
\n '),t.forEach(function(t,a){var c=a>0,l=c?"checked":"",u=c?"":''.concat((0,i.Tl)("budget","keep"),""),d=t.billId?''.concat((0,i.Tl)("budget","bill"),""):"",h="scheduled"===t.status?''.concat((0,i.Tl)("budget","scheduled"),""):"pending"===t.status?''.concat((0,i.Tl)("budget","pending"),""):"";r+='\n \n ")}),r+="
"}),r+="
",t.innerHTML=r,t.addEventListener("change",function(t){t.target.classList.contains("duplicate-checkbox")&&n.updateDuplicatesSelectedCount()}),document.getElementById("duplicates-delete-btn").addEventListener("click",function(){n.deleteDuplicates()}),document.getElementById("duplicates-select-none-btn").addEventListener("click",function(){t.querySelectorAll(".duplicate-checkbox").forEach(function(t){return t.checked=!1}),n.updateDuplicatesSelectedCount()})}},{key:"updateDuplicatesSelectedCount",value:function(){var t=document.querySelectorAll(".duplicate-checkbox:checked"),e=document.getElementById("duplicates-selected-count"),n=document.getElementById("duplicates-delete-btn");e&&(e.textContent=t.length),n&&(n.disabled=0===t.length)}},{key:"deleteDuplicates",value:(t=Se(Te().m(function t(){var e,n,a,r,o,s,u;return Te().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.querySelectorAll(".duplicate-checkbox:checked"),0!==(n=Array.from(e).map(function(t){return parseInt(t.dataset.txId)})).length){t.n=1;break}return t.a(2);case 1:return a=Array.from(e).filter(function(t){var e=t.closest(".duplicate-item");return e&&e.querySelector(".bill-badge")}).length,r=(0,i.zw)("budget","Delete %n suspected duplicate transaction? This cannot be undone.","Delete %n suspected duplicate transactions? This cannot be undone.",n.length),a>0&&(r+="\n\n"+(0,i.zw)("budget","%n of these was generated from bill payments. Make sure they are truly duplicates before deleting.","%n of these were generated from bill payments. Make sure they are truly duplicates before deleting.",a)),t.n=2,(0,l.ZD)(r,{destructive:!0});case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return(o=document.getElementById("duplicates-delete-btn")).disabled=!0,o.textContent=(0,i.Tl)("budget","Deleting..."),t.p=4,t.n=5,(0,T.n)("/apps/budget/api/transactions/bulk-delete",{method:"POST",body:{ids:n}});case 5:(s=t.v).success>0&&((0,c.Te)((0,i.zw)("budget","Deleted %n duplicate transaction","Deleted %n duplicate transactions",s.success)),this._duplicatesDirty=!0,e.forEach(function(t){var e=t.closest(".duplicate-item");e&&e.remove()}),document.querySelectorAll(".duplicate-group").forEach(function(t){t.querySelectorAll(".duplicate-item").length<=1&&t.remove()}),this.updateDuplicatesSelectedCount(),0===document.querySelectorAll(".duplicate-group").length&&(document.getElementById("duplicates-content").innerHTML='

'.concat((0,i.Tl)("budget","All duplicates have been resolved."),"

"))),s.failed>0&&(0,c.Qg)((0,i.zw)("budget","Failed to delete %n transaction","Failed to delete %n transactions",s.failed)),t.n=7;break;case 6:t.p=6,u=t.v,console.error("Failed to delete duplicates:",u),(0,c.Qg)((0,i.Tl)("budget","Failed to delete duplicates"));case 7:return t.p=7,o&&document.body.contains(o)&&(o.disabled=!1,o.textContent=(0,i.Tl)("budget","Delete Selected")+" (".concat(document.querySelectorAll(".duplicate-checkbox:checked").length,")")),t.f(7);case 8:return t.a(2)}},t,this,[[4,6,7,8]])})),function(){return t.apply(this,arguments)})}]);var t,e,n,a,r,d,h,p,f,m,v,y,E,x,S,C,I,A,_,M,D,B,L,P,O,F,R,N,j,H,z,V,q,W,U,G,Z,Y,Q,$,K,X,J,tt,et,nt,at,rt,it,ot,st,ct,lt,ut,dt,ht,gt,pt}(),Oe=n(192);function Fe(t){return Fe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Fe(t)}function Re(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=je(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var a=0,r=function(){};return{s:r,n:function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,o=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return o=t.done,t},e:function(t){s=!0,i=t},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw i}}}}function Ne(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var a,r,i,o,s=[],c=!0,l=!1;try{if(i=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(a=i.call(n)).done)&&(s.push(a.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw r}}return s}}(t,e)||je(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function je(t,e){if(t){if("string"==typeof t)return He(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?He(t,e):void 0}}function He(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,a=Array(e);n3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(Ve(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,Ve(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,Ve(d,"constructor",l),Ve(l,"constructor",c),c.displayName="GeneratorFunction",Ve(l,r,"GeneratorFunction"),Ve(d),Ve(d,r,"Generator"),Ve(d,a,function(){return this}),Ve(d,"toString",function(){return"[object Generator]"}),(ze=function(){return{w:i,m:h}})()}function Ve(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}Ve=function(t,e,n,a){function i(e,n){Ve(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},Ve(t,e,n,a)}function qe(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function We(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){qe(i,a,r,o,s,"next",t)}function s(t){qe(i,a,r,o,s,"throw",t)}o(void 0)})}}function Ue(t,e){for(var n=0;n0?Math.min(Math.max(a/r*100,0),100):0,l=a>=r,u=null!=t.tagId,d=t.color||"#0082c9",h=t.targetDate||t.target_date,p=!0===t._shared,f=!p||!0===t._canWrite,m=!p||!0===t._canManage,v=t.userId||t.user_id||"",y="";if(h){var b=o.Zj(h),w=new Date,T=Math.ceil((b-w)/864e5);y=T<0?(0,i.Tl)("budget","Target date passed"):0===T?(0,i.Tl)("budget","Target date: Today"):T<=30?(0,i.zw)("budget","%n day left","%n days left",T):(0,i.Tl)("budget","Target: {date}",{date:o.Yq(h,e.settings)})}n=l?' '.concat((0,i.Tl)("budget","Goal reached!"),""):u?' '.concat((0,i.Tl)("budget","Auto-tracked"),""):f?'"):"";var k=p?' ').concat((0,i.Tl)("budget","Shared"),""):"";return'\n
\n
\n
\n \n

').concat(s.ZD(t.name),"

\n ").concat(k,'\n
\n
\n ').concat(f?''):"","\n ").concat(m?''):"",'\n
\n
\n\n
\n
\n
\n
\n
\n ').concat(o.vv(a,null,e.settings),'\n ').concat(c.toFixed(0),'%\n ').concat((0,i.Tl)("budget","of {amount}",{amount:o.vv(r,null,e.settings)}),'\n
\n
\n\n \n
\n ")}).join("")}},{key:"setupGoalsEventListeners",value:function(){var t,e,n,a,r,i,o,s=this;null===(t=document.getElementById("add-goal-btn"))||void 0===t||t.addEventListener("click",function(){s.showGoalModal()}),null===(e=document.getElementById("empty-goals-add-btn"))||void 0===e||e.addEventListener("click",function(){s.showGoalModal()}),null===(n=document.getElementById("goal-form"))||void 0===n||n.addEventListener("submit",function(){var t=We(ze().m(function t(e){return ze().w(function(t){for(;;)switch(t.n){case 0:return e.preventDefault(),t.n=1,s.saveGoal();case 1:return t.a(2)}},t)}));return function(e){return t.apply(this,arguments)}}()),null===(a=document.getElementById("add-to-goal-form"))||void 0===a||a.addEventListener("submit",function(){var t=We(ze().m(function t(e){return ze().w(function(t){for(;;)switch(t.n){case 0:return e.preventDefault(),t.n=1,s.addMoneyToGoal();case 1:return t.a(2)}},t)}));return function(e){return t.apply(this,arguments)}}()),null===(r=document.getElementById("goals-list"))||void 0===r||r.addEventListener("click",function(t){var e=t.target.closest(".edit-goal-btn"),n=t.target.closest(".delete-goal-btn"),a=t.target.closest(".goal-add-money-btn");if(e){var r=parseInt(e.dataset.goalId);s.editGoal(r)}else if(n){var i=parseInt(n.dataset.goalId);s.deleteGoal(i)}else if(a){var o=parseInt(a.dataset.goalId);s.showAddMoneyModal(o)}});var c=document.getElementById("goal-modal");c&&c.querySelectorAll(".cancel-btn").forEach(function(t){t.addEventListener("click",function(){c.style.display="none"})});var l=document.getElementById("add-to-goal-modal");l&&l.querySelectorAll(".cancel-btn").forEach(function(t){t.addEventListener("click",function(){l.style.display="none"})}),null===(i=document.getElementById("goal-tag"))||void 0===i||i.addEventListener("change",function(t){s.updateCurrentAmountFieldState(""!==t.target.value)}),null===(o=document.getElementById("goal-color"))||void 0===o||o.addEventListener("input",function(t){var e=document.getElementById("goal-color-preview");e&&(e.style.backgroundColor=t.target.value)})}},{key:"updateCurrentAmountFieldState",value:function(t){var e=document.getElementById("goal-current"),n=document.getElementById("goal-tag-hint");e&&(e.disabled=t,t?(e.value="",e.placeholder=(0,i.Tl)("budget","Auto-calculated from tag")):e.placeholder="0.00"),n&&(n.style.display=t?"block":"none")}},{key:"populateGoalAccountDropdown",value:function(){var t=document.getElementById("goal-account");t&&(t.innerHTML='")+(0,k.ig)(this.accounts,t.value,{readOnlyShares:!0}).map(function(t){return'")}).join(""))}},{key:"populateGoalTagDropdown",value:(a=We(ze().m(function t(){var e,n,a,r,o,c,l,u,d,h,g,p,f,m,v,y,b,w,k=this;return ze().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.getElementById("goal-tag")){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,Promise.all([(0,T.n)("/apps/budget/api/tag-sets"),(0,T.n)("/apps/budget/api/tags/global").catch(function(){return null})]);case 2:if(n=t.v,a=Ne(n,2),r=a[0],o=a[1],this._allTagSets=r,this._goalTagsById=new Map,c='"),o&&(o.forEach(function(t){return k._goalTagsById.set(t.id,t)}),(l=(0,ne.g)(o)).length>0)){c+=''),u=Re(l);try{for(u.s();!(d=u.n()).done;)h=d.value,c+='")}catch(t){u.e(t)}finally{u.f()}c+=""}g=Re(this._allTagSets);try{for(g.s();!(p=g.n()).done;)if(((f=p.value).tags||[]).forEach(function(t){return k._goalTagsById.set(t.id,t)}),(m=(0,ne.g)(f.tags)).length>0){c+=''),v=Re(m);try{for(v.s();!(y=v.n()).done;)b=y.value,c+='")}catch(t){v.e(t)}finally{v.f()}c+=""}}catch(t){g.e(t)}finally{g.f()}e.innerHTML=c,t.n=4;break;case 3:t.p=3,w=t.v,console.error("Failed to load tags for goal dropdown:",w);case 4:return t.a(2)}},t,this,[[1,3]])})),function(){return a.apply(this,arguments)})},{key:"ensureGoalTagOption",value:function(t){var e,n=document.getElementById("goal-tag");if(n&&t&&!n.querySelector('option[value="'.concat(t,'"]'))){var a=null===(e=this._goalTagsById)||void 0===e?void 0:e.get(t);if(a){var r=document.createElement("option");r.value=String(a.id),r.textContent=a.name,n.appendChild(r)}}}},{key:"showGoalModal",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,e=document.getElementById("goal-modal"),n=document.getElementById("goal-modal-title"),a=document.getElementById("goal-form");if(e&&a){n.textContent=t?(0,i.Tl)("budget","Edit Savings Goal"):(0,i.Tl)("budget","Add Savings Goal"),a.reset(),document.getElementById("goal-id").value="",document.getElementById("goal-color").value="#0082c9",(0,u.N1)("goal-target-date");var r=document.getElementById("goal-tag");if(r&&(r.value=""),this.updateCurrentAmountFieldState(!1),t){document.getElementById("goal-id").value=t.id,document.getElementById("goal-name").value=t.name,document.getElementById("goal-target").value=t.targetAmount||t.target_amount||"",document.getElementById("goal-current").value=t.currentAmount||t.current_amount||0,(0,u.Mv)("goal-target-date",t.targetDate||t.target_date||""),document.getElementById("goal-notes").value=t.description||"",r&&t.tagId&&(this.ensureGoalTagOption(t.tagId),r.value=t.tagId,this.updateCurrentAmountFieldState(!0));var o=document.getElementById("goal-account");o&&t.accountId&&(0,k.XH)(o,this.accounts,t.accountId),t.color&&(document.getElementById("goal-color").value=t.color)}e.style.display="flex"}}},{key:"saveGoal",value:function(){var t=this;return(0,ee.O)("goal-save",document.querySelector('#goal-form [type="submit"]'),function(){return t._saveGoal()})}},{key:"_saveGoal",value:(n=We(ze().m(function t(){var e,n,a,r,o,s,l,u,d,h,g,p,f;return ze().w(function(t){for(;;)switch(t.p=t.n){case 0:return r=document.getElementById("goal-id").value,o=null===(e=document.getElementById("goal-tag"))||void 0===e?void 0:e.value,s=document.getElementById("goal-target-date").value,l=document.getElementById("goal-notes").value,u=null===(n=document.getElementById("goal-account"))||void 0===n?void 0:n.value,d=null===(a=document.getElementById("goal-color"))||void 0===a?void 0:a.value,h={name:document.getElementById("goal-name").value,targetAmount:parseFloat(document.getElementById("goal-target").value)||0,currentAmount:parseFloat(document.getElementById("goal-current").value)||0,targetDate:s||null,description:l||null,tagId:o?parseInt(o):null,accountId:u?parseInt(u):null,color:d||null},t.p=1,g=r?"/apps/budget/api/savings-goals/".concat(r):"/apps/budget/api/savings-goals",t.p=2,t.n=3,(0,T.n)(g,{method:r?"PUT":"POST",body:h,errorMessage:(0,i.Tl)("budget","Failed to save goal")});case 3:t.n=6;break;case 4:if(t.p=4,(p=t.v)instanceof T.h){t.n=5;break}throw p;case 5:return console.error("Save goal error response:",p.status,p.data),(0,c.Qg)(p.message),t.a(2);case 6:return document.getElementById("goal-modal").style.display="none",(0,c.Te)(r?(0,i.Tl)("budget","Goal updated"):(0,i.Tl)("budget","Goal created")),t.n=7,this.loadSavingsGoalsView();case 7:t.n=9;break;case 8:t.p=8,f=t.v,console.error("Failed to save goal:",f),(0,c.Qg)((0,i.Tl)("budget","Failed to save goal"));case 9:return t.a(2)}},t,this,[[2,4],[1,8]])})),function(){return n.apply(this,arguments)})},{key:"editGoal",value:function(t){var e,n=null===(e=this.savingsGoals)||void 0===e?void 0:e.find(function(e){return e.id===t});n&&this.showGoalModal(n)}},{key:"deleteGoal",value:(e=We(ze().m(function t(e){var n;return ze().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.n=1,(0,l.ZD)((0,i.Tl)("budget","Are you sure you want to delete this savings goal?"),{destructive:!0});case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/savings-goals/".concat(e),{method:"DELETE"});case 3:return(0,c.Te)((0,i.Tl)("budget","Goal deleted")),t.n=4,this.loadSavingsGoalsView();case 4:t.n=6;break;case 5:t.p=5,n=t.v,console.error("Failed to delete goal:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to delete goal"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(t){return e.apply(this,arguments)})},{key:"showAddMoneyModal",value:function(t){var e,n=null===(e=this.savingsGoals)||void 0===e?void 0:e.find(function(e){return e.id===t});if(n)if(n.tagId)(0,c.cf)((0,i.Tl)("budget","This goal is auto-tracked via a tag"));else{var a=document.getElementById("add-to-goal-modal");document.getElementById("add-to-goal-name").textContent=n.name,document.getElementById("add-to-goal-id").value=t,document.getElementById("add-amount").value="",a.style.display="flex"}}},{key:"addMoneyToGoal",value:function(){var t=this;return(0,ee.O)("goal-add-money",document.querySelector('#add-to-goal-form [type="submit"]'),function(){return t._addMoneyToGoal()})}},{key:"_addMoneyToGoal",value:(t=We(ze().m(function t(){var e,n,a,r,s,l,u;return ze().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=document.getElementById("add-to-goal-id").value,!((a=parseFloat(document.getElementById("add-amount").value)||0)<=0)){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please enter a valid amount")),t.a(2);case 1:if(r=null===(e=this.savingsGoals)||void 0===e?void 0:e.find(function(t){return t.id===parseInt(n)})){t.n=2;break}return t.a(2);case 2:if(!r.tagId){t.n=3;break}return(0,c.cf)((0,i.Tl)("budget","This goal is auto-tracked via a tag")),t.a(2);case 3:return s=parseFloat(r.currentAmount||r.current_amount)||0,l=s+a,t.p=4,t.n=5,(0,T.n)("/apps/budget/api/savings-goals/".concat(n),{method:"PUT",body:{currentAmount:l}});case 5:return document.getElementById("add-to-goal-modal").style.display="none",(0,c.Te)((0,i.Tl)("budget","Added {amount} to goal",{amount:o.vv(a,null,this.settings)})),t.n=6,this.loadSavingsGoalsView();case 6:t.n=8;break;case 7:t.p=7,u=t.v,console.error("Failed to add money to goal:",u),(0,c.Qg)((0,i.Tl)("budget","Failed to add money to goal"));case 8:return t.a(2)}},t,this,[[4,7]])})),function(){return t.apply(this,arguments)})}]);var t,e,n,a,r}(),Ye=n(42),Qe=n(958),$e=n(69),Ke=n(10);function Xe(t){return Xe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Xe(t)}function Je(){var t,e,n="function"==typeof Symbol?Symbol:{},a=n.iterator||"@@iterator",r=n.toStringTag||"@@toStringTag";function i(n,a,r,i){var c=a&&a.prototype instanceof s?a:s,l=Object.create(c.prototype);return tn(l,"_invoke",function(n,a,r){var i,s,c,l=0,u=r||[],d=!1,h={p:0,n:0,v:t,a:g,f:g.bind(t,4),d:function(e,n){return i=e,s=0,c=t,h.n=n,o}};function g(n,a){for(s=n,c=a,e=0;!d&&l&&!r&&e3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(tn(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,tn(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,tn(d,"constructor",l),tn(l,"constructor",c),c.displayName="GeneratorFunction",tn(l,r,"GeneratorFunction"),tn(d),tn(d,r,"Generator"),tn(d,a,function(){return this}),tn(d,"toString",function(){return"[object Generator]"}),(Je=function(){return{w:i,m:h}})()}function tn(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}tn=function(t,e,n,a){function i(e,n){tn(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},tn(t,e,n,a)}function en(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function nn(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){en(i,a,r,o,s,"next",t)}function s(t){en(i,a,r,o,s,"throw",t)}o(void 0)})}}function an(t,e){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:void 0,u=!(0,k.kq)(t),d=void 0===l||(0,k.Zg)(t,l),h=t.frequency||"monthly",g=null===(a=null!==(r=t.isActive)&&void 0!==r?r:t.is_active)||void 0===a||a,p="one-time"===h,f=t.nextExpectedDate||t.next_expected_date||null,m=t.lastReceivedDate||t.last_received_date||null,v=t.startDate||t.start_date||null,y=function(t){return o.Yq(t,n)},b=!(null===(s=t.lastOccurrenceSkipped)||void 0===s||!s),w=(0,$e.L)({frequency:h,isActive:g,dueDate:f,lastDate:m,skipped:b},e),T=w.status,E=w.recentlySettled;if("inactive"===T)return c=m?(0,i.Tl)("budget","Received {date}",{date:y(m)}):p&&v?y(v):(0,i.Tl)("budget","No date set"),{status:p?"completed":"inactive",statusText:p?(0,i.Tl)("budget","Completed"):(0,i.Tl)("budget","Inactive"),dateText:c,canReceive:!1,canSkip:!1,canWrite:u,accountHint:null};var x={overdue:"overdue",soon:"expected-soon",settled:"received",upcoming:"upcoming"}[T],S="received"!==x&&u;return{status:x,statusText:{overdue:(0,i.Tl)("budget","Overdue"),"expected-soon":(0,i.Tl)("budget","Expected Soon"),received:(0,i.Tl)("budget","Received"),upcoming:(0,i.Tl)("budget","Upcoming")}[x],dateText:E?(0,i.Tl)("budget","Received {receivedDate}, next expected {expectedDate}",{receivedDate:y(m),expectedDate:y(f)}):y(f),canReceive:S&&d,canSkip:S&&!p,canWrite:u,accountHint:!S||d||t._shared?null:(0,i.Tl)("budget","This income uses an account you can no longer change. Edit it and choose another account.")}}(t,r,e.settings,e.accounts),l=c.status,u=c.statusText,d=t.frequency||"monthly",h={weekly:(0,i.Tl)("budget","Weekly"),biweekly:(0,i.Tl)("budget","Bi-Weekly"),"semi-monthly":(0,i.Tl)("budget","Semi-Monthly"),monthly:(0,i.Tl)("budget","Monthly"),quarterly:(0,i.Tl)("budget","Quarterly"),"semi-annually":(0,i.Tl)("budget","Semi-Annually"),yearly:(0,i.Tl)("budget","Yearly"),"one-time":(0,i.Tl)("budget","One-Time")}[d]||d.charAt(0).toUpperCase()+d.slice(1),g=t.source||"",p=null!==(n=null!==(a=t.autoCreateEnabled)&&void 0!==a?a:t.auto_create_enabled)&&void 0!==n&&n;return'\n
\n
\n
\n

').concat(s.ZD(t.name),'

\n ').concat(h,"\n ").concat(g?''.concat(s.ZD(g),""):"",'\n
\n
').concat(o.vv(t.amount,t.currency||(0,k.$S)(e.accounts,t.accountId),e.settings),'
\n
\n
\n
\n \n ').concat(s.ZD(c.dateText),'\n
\n
\n ').concat(u,"\n ").concat(p?' ').concat((0,i.Tl)("budget","Auto-create"),""):"","\n
\n
\n ").concat(c.accountHint?'"):"",'\n
\n ').concat(c.canReceive?'\n \n "):"","\n ").concat(c.canSkip?'\n \n "):"","\n ").concat(c.canWrite?''):"","\n ").concat(t._shared&&!t._canManage?"":''),"\n
\n
\n ")}).join("")}},{key:"filterIncome",value:function(t){document.querySelectorAll(".income-card").forEach(function(e){var n=e.dataset.status,a=!1;switch(t){case"all":default:a=!0;break;case"expected":a="expected-soon"===n||"upcoming"===n||"overdue"===n;break;case"received":a="received"===n||"completed"===n}e.style.display=a?"flex":"none"})}},{key:"setupIncomeEventListeners",value:function(){var t=this,e=document.getElementById("add-income-btn"),n=document.getElementById("empty-income-add-btn");e&&e.addEventListener("click",function(){return t.showIncomeModal()}),n&&n.addEventListener("click",function(){return t.showIncomeModal()});var a=document.getElementById("detect-income-btn");a&&a.addEventListener("click",function(){return t.detectIncome()});var r=document.getElementById("close-detected-income-panel");r&&r.addEventListener("click",function(){document.getElementById("detected-income-panel").style.display="none"});var i=document.getElementById("cancel-detected-income-btn");i&&i.addEventListener("click",function(){document.getElementById("detected-income-panel").style.display="none"});var o=document.getElementById("add-selected-income-btn");o&&o.addEventListener("click",function(){return t.addSelectedDetectedIncome()});var s=document.getElementById("income-form");s&&s.addEventListener("submit",function(e){e.preventDefault(),t.saveIncome()});var c=document.getElementById("income-modal");c&&(c.querySelectorAll(".cancel-btn").forEach(function(e){e.addEventListener("click",function(){return t.hideIncomeModal()})}),c.addEventListener("click",function(e){e.target===c&&t.hideIncomeModal()}));var l=document.getElementById("income-account"),u=document.getElementById("income-auto-create");l&&u&&(l.addEventListener("change",function(){l.value&&""!==l.value?u.disabled=!1:(u.checked=!1,u.disabled=!0)}),l.value&&""!==l.value||(u.disabled=!0));var d=document.getElementById("income-frequency");d&&d.addEventListener("change",function(){return t.updateIncomeFormFields()});var h=document.getElementById("income-start-date");h&&h.addEventListener("change",function(){return t.updateIncomeFormFields()});var g=document.querySelectorAll(".income-tabs .tab-button");g.forEach(function(e){e.addEventListener("click",function(){g.forEach(function(t){return t.classList.remove("active")}),e.classList.add("active"),t.filterIncome(e.dataset.filter)})});var p=document.getElementById("income-list");p&&p.addEventListener("click",function(e){var n=e.target.closest(".income-edit-btn"),a=e.target.closest(".income-delete-btn"),r=e.target.closest(".income-received-btn"),i=e.target.closest(".income-skip-btn");if(n){var o=parseInt(n.dataset.incomeId),s=t.recurringIncome.find(function(t){return t.id===o});s&&t.showIncomeModal(s)}if(a){var c=parseInt(a.dataset.incomeId);t.deleteIncome(c)}if(!r&&!i||!(0,re.u$)(e)){var l=function(t){return'#income-list .income-card[data-income-id="'.concat(t,'"]')};if(r){var u=parseInt(r.dataset.incomeId);(0,Ye.m)(e,l(u),".income-received-btn",function(){return t.markIncomeReceived(u,r)})}if(i){var d=parseInt(i.dataset.incomeId);(0,Ye.m)(e,l(d),".income-skip-btn",function(){return t.skipIncome(d,i)})}}})}},{key:"showIncomeModal",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,e=document.getElementById("income-modal"),n=document.getElementById("income-modal-title");if(document.getElementById("income-form").reset(),document.getElementById("income-id").value="",(0,w.c2)(["income-category","income-account"]),t){var a,r,o,s,c,l,d,h;n.textContent=(0,i.Tl)("budget","Edit Recurring Income"),document.getElementById("income-id").value=t.id,document.getElementById("income-name").value=t.name||"",document.getElementById("income-description").value=t.description||"",document.getElementById("income-amount").value=t.amount||"",document.getElementById("income-source").value=t.source||"",document.getElementById("income-frequency").value=t.frequency||"monthly",document.getElementById("income-expected-day").value=t.expectedDay||t.expected_day||"",document.getElementById("income-expected-month").value=t.expectedMonth||t.expected_month||"",(0,w.Qz)(document.getElementById("income-category"),null!==(a=null!==(r=t.categoryId)&&void 0!==r?r:t.category_id)&&void 0!==a?a:null,t.categoryName?(0,w.pC)(t.categoryName):null);var g=document.getElementById("income-account"),p=null!==(o=null!==(s=t.accountId)&&void 0!==s?s:t.account_id)&&void 0!==o?o:null;(0,k.XH)(g,this.accounts,p)||(0,w.Qz)(g,p),document.getElementById("income-auto-pattern").value=t.autoDetectPattern||t.auto_detect_pattern||"",document.getElementById("income-notes").value=t.notes||"",(0,u.Mv)("income-start-date",t.startDate||t.start_date||"");var f=null!==(c=null!==(l=t.autoCreateEnabled)&&void 0!==l?l:t.auto_create_enabled)&&void 0!==c&&c;document.getElementById("income-auto-create").checked=f;var m=document.getElementById("income-excluded-from-forecast");m&&(m.checked=null!==(d=null!==(h=t.excludedFromForecast)&&void 0!==h?h:t.excluded_from_forecast)&&void 0!==d&&d)}else{n.textContent=(0,i.Tl)("budget","Add Recurring Income"),document.getElementById("income-auto-create").checked=!1;var v=document.getElementById("income-excluded-from-forecast");v&&(v.checked=!1),(0,u.N1)("income-start-date")}this.updateIncomeFormFields(),e.style.display="flex",e.setAttribute("aria-hidden","false")}},{key:"hideIncomeModal",value:function(){var t=document.getElementById("income-modal");t.style.display="none",t.setAttribute("aria-hidden","true")}},{key:"updateIncomeFormFields",value:function(){var t,e=document.getElementById("income-frequency").value,n=document.getElementById("expected-day-group"),a=document.getElementById("expected-month-group"),r="one-time"===e,o=document.getElementById("income-account"),s=document.getElementById("income-auto-create");o&&s&&(o.value&&""!==o.value?s.disabled=!1:(s.checked=!1,s.disabled=!0));var c=document.getElementById("income-start-date-group"),l=document.getElementById("income-start-date");if(c){c.style.display="weekly"===e||"biweekly"===e||r?"block":"none";var u=c.querySelector("label"),d=document.getElementById("income-start-date-help");u&&(u.textContent=r?(0,i.Tl)("budget","Date"):(0,i.Tl)("budget","First payment date")),d&&(d.textContent=r?(0,i.Tl)("budget","The date this income is expected. It can be in the past."):(0,i.Tl)("budget","Payments repeat from this date (optional)")),l&&(l.required=r)}if(r)return n.style.display="none",void(a.style.display="none");n.style.display="block",a.style.display="yearly"===e||"semi-annually"===e||"quarterly"===e?"block":"none";var h=n.querySelector("label"),g=document.getElementById("income-expected-day-help"),p=document.getElementById("income-expected-day");"weekly"===e||"biweekly"===e?(h.textContent=(0,i.Tl)("budget","Expected Day (1-7)"),g.textContent=(0,i.Tl)("budget","Day of the week (1=Monday, 7=Sunday)"),p.max=7):(h.textContent=(0,i.Tl)("budget","Expected Day"),g.textContent=(0,i.Tl)("budget","Day of the month when income is expected"),p.max=31);var f=("weekly"===e||"biweekly"===e)&&(null===(t=document.getElementById("income-start-date"))||void 0===t?void 0:t.value)||"";f?(p.value=String((0,b.mg)(f)),p.disabled=!0,g.textContent=(0,i.Tl)("budget","Follows the start date")):p.disabled=!1}},{key:"populateIncomeModalDropdowns",value:function(){var t=document.getElementById("income-category");if(t&&this.categories){var e=t.value;t.innerHTML='"),s.Vb(t,this.categoryTree||this.categories,{typeFilter:"income"}),e&&(t.value=e)}var n=document.getElementById("income-account");if(n&&this.accounts){var a=n.value;n.innerHTML='"),(0,k.ig)(this.accounts,a).forEach(function(t){var e=t.currency?" (".concat(s.ZD(t.currency),")"):"";n.innerHTML+='")}),a&&(n.value=a)}}},{key:"saveIncome",value:function(){var t=this;return(0,ee.O)("income-save",document.querySelector('#income-form [type="submit"]'),function(){return t._saveIncome()})}},{key:"_saveIncome",value:(p=nn(Je().m(function t(){var e,n,a,r,o,s,l,u,d,h,g,p,f,m;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:if(t.p=0,o=document.getElementById("income-id").value,s=!o,l=document.getElementById("income-frequency").value,u="weekly"===l||"biweekly"===l,d="one-time"===l,h=(null===(e=document.getElementById("income-start-date"))||void 0===e?void 0:e.value)||null,!d||h){t.n=1;break}return(0,c.Qg)((0,i.Tl)("budget","Choose the date this income is expected")),t.a(2);case 1:return g="yearly"===l||"semi-annually"===l||"quarterly"===l,p={name:document.getElementById("income-name").value.trim(),description:(null===(n=document.getElementById("income-description"))||void 0===n?void 0:n.value.trim())||null,amount:parseFloat(document.getElementById("income-amount").value)||0,source:document.getElementById("income-source").value.trim()||null,frequency:l,expectedDay:parseInt(document.getElementById("income-expected-day").value)||null,expectedMonth:g&&parseInt(document.getElementById("income-expected-month").value)||null,categoryId:parseInt(document.getElementById("income-category").value)||null,accountId:parseInt(document.getElementById("income-account").value)||null,autoDetectPattern:document.getElementById("income-auto-pattern").value.trim()||null,notes:document.getElementById("income-notes").value.trim()||null,autoCreateEnabled:(null===(a=document.getElementById("income-auto-create"))||void 0===a?void 0:a.checked)||!1,excludedFromForecast:(null===(r=document.getElementById("income-excluded-from-forecast"))||void 0===r?void 0:r.checked)||!1,startDate:u||d?h:null},f=s?"/apps/budget/api/recurring-income":"/apps/budget/api/recurring-income/".concat(o),t.n=2,(0,T.n)(f,{method:s?"POST":"PUT",body:p});case 2:return this.hideIncomeModal(),(0,c.Te)(s?(0,i.Tl)("budget","Income source created successfully"):(0,i.Tl)("budget","Income source updated successfully")),t.n=3,this.loadIncomeView();case 3:t.n=5;break;case 4:t.p=4,m=t.v,console.error("Failed to save income:",m),(0,c.Qg)(m.message||(0,i.Tl)("budget","Failed to save income"));case 5:return t.a(2)}},t,this,[[0,4]])})),function(){return p.apply(this,arguments)})},{key:"deleteIncome",value:(g=nn(Je().m(function t(e){var n;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.n=1,(0,l.ZD)((0,i.Tl)("budget","Are you sure you want to delete this recurring income?"),{destructive:!0});case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/recurring-income/".concat(e),{method:"DELETE"});case 3:return(0,c.Te)((0,i.Tl)("budget","Income source deleted successfully")),t.n=4,this.loadIncomeView();case 4:t.n=6;break;case 5:t.p=5,n=t.v,console.error("Failed to delete income:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to delete income"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(t){return g.apply(this,arguments)})},{key:"markIncomeReceived",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return(0,ee.O)("income-received-".concat(t),n,function(){return e._markIncomeReceived(t)})}},{key:"_markIncomeReceived",value:(h=nn(Je().m(function t(e){var n,a,r,s,l,u,d=this;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:if(t.p=0,n=this.recurringIncome.find(function(t){return t.id===e})){t.n=1;break}throw new Error("Income not found");case 1:return a=o.rT(),t.n=2,(0,Ke.Fd)("/apps/budget/api/recurring-income/".concat(e,"/received"),{receivedDate:a,createTransaction:!0,expectedDate:n.nextExpectedDate||n.next_expected_date||null},this.settings,{kind:"income",currency:n.currency||(0,k.$S)(this.accounts,n.accountId)});case 2:if(null!==(r=t.v)){t.n=3;break}return t.a(2);case 3:return s={incomeId:e,action:"markReceived"},this._undoData=s,t.n=4,this.loadIncomeView();case 4:this._undoTimer&&clearTimeout(this._undoTimer),l=r.usedPayment?(0,i.Tl)("budget","Marked as received with the payment of {date}",{date:o.Yq(r.usedPayment.date,this.settings)}):n.accountId?(0,i.Tl)("budget","Income marked as received. Transaction created."):(0,i.Tl)("budget","Income marked as received."),(0,c.JC)(l,function(){return d.undoMarkReceived(s)},function(){return d._dropUndo(s)}),t.n=6;break;case 5:return t.p=5,u=t.v,console.error("Failed to mark income as received:",u),(0,c.Qg)(u.message||(0,i.Tl)("budget","Failed to mark income as received")),t.n=6,this._reloadAfterRefusal(u);case 6:return t.a(2)}},t,this,[[0,5]])})),function(t){return h.apply(this,arguments)})},{key:"_reloadAfterRefusal",value:(d=nn(Je().m(function t(e){return Je().w(function(t){for(;;)switch(t.n){case 0:if(!(e instanceof T.h)){t.n=1;break}return t.n=1,this.loadIncomeView();case 1:return t.a(2)}},t,this)})),function(t){return d.apply(this,arguments)})},{key:"_dropUndo",value:function(t){t.spent=!0,this._undoData===t&&(this._undoData=null)}},{key:"undoMarkReceived",value:(r=nn(Je().m(function t(){var e,n,a,r=arguments;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:if((e=r.length>0&&void 0!==r[0]?r[0]:this._undoData)&&!e.spent&&"markReceived"===e.action){t.n=1;break}return t.a(2);case 1:return e.spent=!0,t.p=2,n=e.incomeId,t.n=3,(0,T.n)("/apps/budget/api/recurring-income/".concat(n,"/unreceived"),{method:"POST"});case 3:return this._undoData===e&&(this._undoData=null),t.n=4,this.loadIncomeView();case 4:(0,c.Te)((0,i.Tl)("budget","Action undone")),t.n=6;break;case 5:t.p=5,a=t.v,console.error("Failed to undo mark received:",a),(0,c.Qg)((0,i.Tl)("budget","Failed to undo action: {message}",{message:a.message}));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return r.apply(this,arguments)})},{key:"skipIncome",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return(0,ee.O)("income-received-".concat(t),n,function(){return e._skipIncome(t)})}},{key:"_skipIncome",value:(a=nn(Je().m(function t(e){var n,a,r,o,s,u,d=this;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=this.recurringIncome.find(function(t){return t.id===e})){t.n=1;break}return t.a(2);case 1:return t.n=2,(0,l.ZD)((0,i.Tl)("budget","Skip this payment and advance to the next expected date?"));case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/recurring-income/".concat(e,"/skip"),{method:"POST",body:{expectedDate:n.nextExpectedDate||n.next_expected_date||null},errorMessage:(0,i.Tl)("budget","Failed to skip income")});case 4:return r=t.v,this._undoTimer&&(clearTimeout(this._undoTimer),this._undoTimer=null),o={incomeId:e,previousNextExpectedDate:null!==(a=r.previousNextExpectedDate)&&void 0!==a?a:null,action:"skip"},this._undoData=o,t.n=5,this.loadIncomeView();case 5:s=(0,c.JC)((0,i.Tl)("budget","Payment skipped. Advanced to next expected date."),function(){return d.undoSkipIncome(o)},function(){(0,Qe.LB)(o),d._dropUndo(o)}),(0,Qe.to)(o,"income-".concat(e),o.previousNextExpectedDate,s),t.n=7;break;case 6:return t.p=6,u=t.v,console.error("Failed to skip income:",u),(0,c.Qg)(u.message||(0,i.Tl)("budget","Failed to skip income")),t.n=7,this._reloadAfterRefusal(u);case 7:return t.a(2)}},t,this,[[3,6]])})),function(t){return a.apply(this,arguments)})},{key:"undoSkipIncome",value:(n=nn(Je().m(function t(){var e,n,a,r,o=arguments;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:if((e=o.length>0&&void 0!==o[0]?o[0]:this._undoData)&&!e.spent&&"skip"===e.action){t.n=1;break}return t.a(2);case 1:return e.spent=!0,t.p=2,n=e.incomeId,a=e.previousNextExpectedDate,t.n=3,(0,T.n)("/apps/budget/api/recurring-income/".concat(n,"/undo-skip"),{method:"POST",body:{previousNextExpectedDate:a}});case 3:return(0,Qe.Ib)(e),this._undoData===e&&(this._undoData=null),t.n=4,this.loadIncomeView();case 4:(0,c.Te)((0,i.Tl)("budget","Action undone")),t.n=6;break;case 5:t.p=5,r=t.v,(0,Qe.LB)(e),console.error("Failed to undo skip:",r),(0,c.Qg)((0,i.Tl)("budget","Failed to undo action: {message}",{message:r.message}));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return n.apply(this,arguments)})},{key:"detectIncome",value:(e=nn(Je().m(function t(){var e,n,a;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:return(e=document.getElementById("detect-income-btn")).disabled=!0,e.innerHTML=' '.concat((0,i.Tl)("budget","Detecting...")),t.p=1,t.n=2,(0,T.n)("/apps/budget/api/recurring-income/detect?months=6");case 2:if(0!==(n=t.v).length){t.n=3;break}return(0,c.cf)((0,i.Tl)("budget","No recurring income patterns found in your transactions")),t.a(2);case 3:this._detectedIncome=n,this.renderDetectedIncome(n),document.getElementById("detected-income-panel").style.display="flex",t.n=5;break;case 4:t.p=4,a=t.v,console.error("Failed to detect income:",a),(0,c.Qg)((0,i.Tl)("budget","Failed to detect recurring income"));case 5:return t.p=5,e.disabled=!1,e.innerHTML=' '.concat((0,i.Tl)("budget","Detect Income")),t.f(5);case 6:return t.a(2)}},t,this,[[1,4,5,6]])})),function(){return e.apply(this,arguments)})},{key:"renderDetectedIncome",value:function(t){var e=this;document.getElementById("detected-income-list").innerHTML=t.map(function(t,n){var a=t.confidence>=.8?"high":t.confidence>=.5?"medium":"low",r=Math.round(100*t.confidence),c=(0,k.$S)(e.accounts,t.accountId);return'\n
\n
\n =.7?"checked":"",'>\n
\n
\n
').concat(s.ZD(t.suggestedName),'
\n
\n ').concat(o.vv(t.amount,c,e.settings),'\n ').concat(t.frequency,'\n ').concat((0,i.zw)("budget","%n occurrence","%n occurrences",t.occurrences),'\n ').concat((0,i.Tl)("budget","Source: {source}",{source:s.ZD(t.source)},void 0,{escape:!1}),'\n
\n
\n ').concat((0,i.Tl)("budget","{percent}% confidence",{percent:r}),"\n ").concat(t.amountVariance?'±'.concat(o.vv(t.amountVariance,c,e.settings),""):"","\n
\n
\n
\n ")}).join("")}},{key:"addSelectedDetectedIncome",value:function(){var t=this;return(0,ee.O)("income-add-detected",document.getElementById("add-selected-income-btn"),function(){return t._addSelectedDetectedIncome()})}},{key:"_addSelectedDetectedIncome",value:(t=nn(Je().m(function t(){var e,n,a,r,o,s=this;return Je().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.querySelectorAll('#detected-income-list input[type="checkbox"]:checked'),0!==(n=Array.from(e).map(function(t){return parseInt(t.id.replace("detected-income-",""))})).length){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please select at least one income source to add")),t.a(2);case 1:return a=n.map(function(t){return s._detectedIncome[t]}),t.p=2,t.n=3,(0,T.n)("/apps/budget/api/recurring-income/create-from-detected",{method:"POST",body:{incomes:a}});case 3:return r=t.v,document.getElementById("detected-income-panel").style.display="none",(0,c.Te)((0,i.zw)("budget","%n income source added successfully","%n income sources added successfully",r.created)),t.n=4,this.loadIncomeView();case 4:t.n=6;break;case 5:t.p=5,o=t.v,console.error("Failed to add income:",o),(0,c.Qg)((0,i.Tl)("budget","Failed to add selected income sources"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return t.apply(this,arguments)})}]);var t,e,n,a,r,d,h,g,p,f,m}(),sn=n(78),cn=n(577),ln=n(574);function un(t){return un="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},un(t)}function dn(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=mn(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var a=0,r=function(){};return{s:r,n:function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,o=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return o=t.done,t},e:function(t){s=!0,i=t},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw i}}}}function hn(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,a)}return n}function gn(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,a=Array(e);n3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(bn(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,bn(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,bn(d,"constructor",l),bn(l,"constructor",c),c.displayName="GeneratorFunction",bn(l,r,"GeneratorFunction"),bn(d),bn(d,r,"Generator"),bn(d,a,function(){return this}),bn(d,"toString",function(){return"[object Generator]"}),(yn=function(){return{w:i,m:h}})()}function bn(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}bn=function(t,e,n,a){function i(e,n){bn(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},bn(t,e,n,a)}function wn(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function Tn(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){wn(i,a,r,o,s,"next",t)}function s(t){wn(i,a,r,o,s,"throw",t)}o(void 0)})}}function kn(t,e){for(var n=0;n\n

'.concat((0,i.Tl)("budget","Recurring Transfers"),'

\n
\n \n \n
\n \n\n \x3c!-- Transfers Summary Cards --\x3e\n
\n
\n
\n \n
\n
\n
0
\n
').concat((0,i.Tl)("budget","Active Transfers"),'
\n
\n
\n
\n
\n \n
\n
\n
0
\n
').concat((0,i.Tl)("budget","Due This Month"),'
\n
\n
\n
\n
\n \n
\n
\n
$0
\n
').concat((0,i.Tl)("budget","Monthly Total"),'
\n
\n
\n
\n
\n \n
\n
\n
0
\n
').concat((0,i.Tl)("budget","Completed This Month"),'
\n
\n
\n
\n\n \x3c!-- Transfers Filter Tabs --\x3e\n
\n \n \n \n \n
\n\n \x3c!-- Transfers List --\x3e\n
\n
\n \x3c!-- Transfers will be rendered here --\x3e\n
\n\n \n\n \x3c!-- Detected Transfers Panel --\x3e\n \n
\n "),this._eventsSetup||(this.setupEventListeners(),this._eventsSetup=!0),this.renderTransfers(),this.updateSummary()):console.error("Transfers view not found")}},{key:"setupEventListeners",value:function(){var t=this;document.addEventListener("click",function(e){if(("add-transfer-btn"===e.target.id||"empty-transfers-add-btn"===e.target.id||e.target.closest("#add-transfer-btn")||e.target.closest("#empty-transfers-add-btn"))&&(e.preventDefault(),t.showTransferModal()),e.target.closest("#detect-transfers-btn")&&(e.preventDefault(),t.detectTransfers()),e.target.closest("#close-detected-transfers-panel")||e.target.closest("#cancel-detected-transfers-btn")){e.preventDefault();var n=document.getElementById("detected-transfers-panel");n&&(n.style.display="none")}e.target.closest("#add-detected-transfers-btn")&&(e.preventDefault(),t.addSelectedDetectedTransfers())});var e=function(t){return'#transfers-list .bill-card[data-bill-id="'.concat(t,'"]')};document.addEventListener("click",function(n){var a=n.target.closest(".transfer-paid-btn");if(a){if(n.preventDefault(),(0,re.u$)(n))return;var r=parseInt(a.dataset.transferId);(0,Ye.m)(n,e(r),".transfer-paid-btn",function(){return t.markTransferPaid(r,a)})}}),document.addEventListener("click",function(n){var a=n.target.closest(".transfer-skip-btn");if(a){if(n.preventDefault(),(0,re.u$)(n))return;var r=parseInt(a.dataset.transferId);(0,Ye.m)(n,e(r),".transfer-skip-btn",function(){return t.skipTransfer(r,a)})}}),document.addEventListener("click",function(n){var a=n.target.closest(".transfer-unpaid-btn");if(a){if(n.preventDefault(),(0,re.u$)(n))return;var r=parseInt(a.dataset.transferId);(0,Ye.m)(n,e(r),".transfer-unpaid-btn",function(){return t.markTransferUnpaid(r,a)})}}),document.addEventListener("click",function(e){var n=e.target.closest(".transfer-edit-btn");if(n){e.preventDefault();var a=parseInt(n.dataset.transferId),r=t.transfers.find(function(t){return t.id===a});r&&t.showTransferModal(r)}}),document.addEventListener("click",function(e){var n=e.target.closest(".transfer-delete-btn");if(n){e.preventDefault();var a=parseInt(n.dataset.transferId);t.deleteTransfer(a)}}),document.addEventListener("click",function(e){var n;if(e.target.classList.contains("tab-button")&&e.target.closest(".bills-tabs")&&null!==(n=document.getElementById("transfers-view"))&&void 0!==n&&n.contains(e.target)){e.preventDefault(),document.querySelectorAll(".bills-tabs .tab-button").forEach(function(t){t.classList.remove("active")}),e.target.classList.add("active");var a=e.target.dataset.filter;t.filterTransfers(a)}})}},{key:"renderTransfers",value:function(){var t=this,e=document.getElementById("transfers-list"),n=document.getElementById("empty-transfers");if(!this.transfers||0===this.transfers.length)return e.innerHTML="",void(n.style.display="flex");n.style.display="none";var a=o.rT();e.innerHTML=this.transfers.map(function(e){var n,r,c,l,u=(0,sn.Zg)(e,a,t.settings,t.accounts),d=u.status,h=u.statusText,g=e.frequency||"monthly",p={"one-time":(0,i.Tl)("budget","One-Time"),weekly:(0,i.Tl)("budget","Weekly"),biweekly:(0,i.Tl)("budget","Bi-Weekly"),"semi-monthly":(0,i.Tl)("budget","Semi-Monthly"),monthly:(0,i.Tl)("budget","Monthly"),quarterly:(0,i.Tl)("budget","Quarterly"),"semi-annually":(0,i.Tl)("budget","Semi-Annually"),yearly:(0,i.Tl)("budget","Yearly")}[g]||g.charAt(0).toUpperCase()+g.slice(1),f=null!==(n=null!==(r=e.autoPayEnabled)&&void 0!==r?r:e.auto_pay_enabled)&&void 0!==n&&n,m=null!==(c=null!==(l=e.autoPayFailed)&&void 0!==l?l:e.auto_pay_failed)&&void 0!==c&&c;return'\n
\n
\n
\n

').concat(s.ZD(e.name),'

\n ').concat(p,'\n
\n
').concat(o.vv(e.amount,e.currency||null,t.settings)).concat(t.amountTypeBadge(e.amountType),'
\n
\n
\n
\n \n ').concat(s.ZD(u.dateText),'\n
\n
\n ').concat(h,"\n ").concat(f?' ').concat((0,i.Tl)("budget","Auto-pay"),""):"","\n ").concat(m?' ').concat((0,i.Tl)("budget","Auto-pay Failed"),""):"","\n
\n
\n ").concat(u.accountHint?'"):"",'\n
\n ').concat(u.canPay?'\n \n "):"","\n ").concat(u.canSkip?'\n \n "):"","\n ").concat(u.canUnpay?'\n \n "):"","\n ").concat(u.canWrite?''):"","\n ").concat(e._shared&&!e._canManage?"":''),"\n
\n
\n ")}).join("")}},{key:"filterTransfers",value:function(t){var e={all:function(){return!0},due:function(t){return"due-soon"===t},overdue:function(t){return"overdue"===t},completed:function(t){return"paid"===t}},n=e[t]||e.all;document.querySelectorAll("#transfers-list .bill-card").forEach(function(t){t.style.display=n(t.dataset.status)?"":"none"})}},{key:"updateSummary",value:(v=Tn(yn().m(function t(){var e,n,a,r,i,s,c,l;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:return e=o.rT(),n=e.slice(0,7),a=this.transfers.filter(function(t){return t.isActive}).length,r=this.transfers.filter(function(t){if(!t.isActive)return!1;var e=t.nextDueDate||t.next_due_date;return!!e&&e.slice(0,7)===n}).length,i=this.transfers.filter(function(t){var e=t.lastPaidDate||t.last_paid_date;return!!e&&e.slice(0,7)===n}).length,document.getElementById("transfers-active-count").textContent=a,document.getElementById("transfers-due-count").textContent=r,document.getElementById("transfers-completed-count").textContent=i,t.p=1,t.n=2,(0,T.n)("/apps/budget/api/bills/summary?isTransfer=true");case 2:s=t.v,(c=document.getElementById("transfers-monthly-total"))&&(c.textContent=o.vv(s.monthlyTotal||0,s.baseCurrency||null,this.settings)),t.n=4;break;case 3:t.p=3,l=t.v,console.error("Failed to load transfers summary:",l);case 4:return t.a(2)}},t,this,[[1,3]])})),function(){return v.apply(this,arguments)})},{key:"showTransferModal",value:function(){var t,e,n,a=this,r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,c=null!==r,l=c?(0,i.Tl)("budget","Edit Transfer"):(0,i.Tl)("budget","Add Transfer"),d='\n \n "),h=document.querySelector(".budget-modal-overlay");h&&h.remove(),document.body.insertAdjacentHTML("beforeend",d),c&&((0,w.Qz)(document.getElementById("transfer-category"),null!==(t=r.categoryId)&&void 0!==t?t:null,r.categoryName?(0,w.pC)(r.categoryName):null),(0,w.Qz)(document.getElementById("recurring-transfer-from-account"),null!==(e=r.accountId)&&void 0!==e?e:null),(0,w.Qz)(document.getElementById("recurring-transfer-to-account"),null!==(n=r.destinationAccountId)&&void 0!==n?n:null));var g=document.getElementById("transfer-transaction-date");g&&(0,u.zH)(g,this.app.settings);var p=document.getElementById("transfer-start-date");p&&((0,u.zH)(p,this.app.settings),p.addEventListener("change",function(){return a.updateTransferScheduleFields()}));var f=document.getElementById("transfer-frequency");f&&f.addEventListener("change",function(){return a.updateTransferScheduleFields()}),this.updateTransferScheduleFields();var m=document.getElementById("transfer-category");m&&m.addEventListener("change",function(){a.loadTransferTagSets(m.value||null,c?r:null)}),this.loadTransferTagSets((null==m?void 0:m.value)||null,c?r:null);var v=document.getElementById("recurring-transfer-to-account"),y=document.getElementById("transfer-amount-type-group"),b=document.getElementById("transfer-amount-type"),T=document.getElementById("transfer-amount-type-hint"),E=document.getElementById("transfer-amount"),x={statement:(0,i.Tl)("budget","Pays what was owed at the due date. Later charges roll to the next payment"),current_balance:(0,i.Tl)("budget","Pays everything owed on the card at payment time"),minimum_payment:(0,i.Tl)("budget","Pays the card's minimum payment, never more than is owed")},S=function(){var t,e=a.accounts.find(function(t){return t.id===parseInt(v.value)}),n=e||"1"!==(null===(t=v.selectedOptions[0])||void 0===t?void 0:t.dataset.unavailable)?!!e&&["credit_card","line_of_credit"].includes(e.type):c&&"fixed"!==(r.amountType||"fixed");n||"fixed"===b.value||(b.value="fixed"),y.style.display=n?"block":"none";var o=n&&"fixed"!==b.value;T.textContent=o?x[b.value]:"",E.disabled=o,E.required=!o,E.placeholder=o?(0,i.Tl)("budget","Resolved from the card at each payment"):""};v.addEventListener("change",S),b.addEventListener("change",S),!c&&o&&(o.name&&(document.getElementById("transfer-name").value=o.name),o.destinationAccountId&&(v.value=String(o.destinationAccountId)),o.dueDay&&(document.getElementById("transfer-due-day").value=String(o.dueDay)),o.amountType&&(b.value=o.amountType)),S();var C=document.getElementById("transfer-create-transaction");C&&C.addEventListener("change",function(t){var e=document.getElementById("transfer-transaction-date-group");e&&(e.style.display=t.target.checked?"block":"none")});var I=document.querySelector(".budget-modal-overlay"),A=document.getElementById("transfer-form"),_=document.getElementById("close-transfer-modal"),M=document.getElementById("cancel-transfer"),D=function(){I.remove()};_.addEventListener("click",D),M.addEventListener("click",D),I.addEventListener("click",function(t){t.target===I&&D()}),A.addEventListener("submit",function(){var t=Tn(yn().m(function t(e){return yn().w(function(t){for(;;)switch(t.n){case 0:return e.preventDefault(),t.n=1,a.saveTransfer(r);case 1:t.v&&D();case 2:return t.a(2)}},t)}));return function(e){return t.apply(this,arguments)}}())}},{key:"updateTransferScheduleFields",value:function(){var t,e=null===(t=document.getElementById("transfer-frequency"))||void 0===t?void 0:t.value,n=document.getElementById("transfer-due-day-group"),a=document.getElementById("transfer-due-day-label"),r=document.getElementById("transfer-due-day"),o=document.getElementById("transfer-due-day-help"),s=document.getElementById("transfer-start-date"),c=document.getElementById("transfer-start-date-group"),l=document.getElementById("transfer-start-date-label"),u=document.getElementById("transfer-start-date-help");if(e&&a&&r){var d="one-time"===e;n&&(n.style.display=d?"none":"block");var h=document.getElementById("transfer-due-month-group");if(h&&(h.style.display=["yearly","semi-annually","quarterly"].includes(e)?"block":"none"),c&&(c.style.display="block"),l&&(l.textContent=d?(0,i.Tl)("budget","Due Date"):(0,i.Tl)("budget","Start Date")),s&&(s.required=d),d)u&&(u.textContent=(0,i.Tl)("budget","The date this transfer is due. It can be in the past."));else{var g="weekly"===e||"biweekly"===e;g?(a.textContent=(0,i.Tl)("budget","Due Day (1-7)"),o&&(o.textContent=(0,i.Tl)("budget","Day of the week (1=Monday, 7=Sunday)")),r.max=7):(a.textContent=(0,i.Tl)("budget","Day of Month (1-31)"),o&&(o.textContent=(0,i.Tl)("budget","Day of the month when the transfer is due")),r.max=31);var p=g&&(null==s?void 0:s.value)||"";p?(r.value=String((0,b.mg)(p)),r.disabled=!0,o&&(o.textContent=(0,i.Tl)("budget","Follows the start date"))):r.disabled=!1,u&&(u.textContent=g?(0,i.Tl)("budget","The transfer repeats from this date (optional)"):(0,i.Tl)("budget","Transfer only occurs on or after this date (optional)"))}}}},{key:"saveTransfer",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return(0,ee.O)("transfer-save",document.querySelector('#transfer-form [type="submit"]'),function(){return t._saveTransfer(e)})}},{key:"_saveTransfer",value:(m=Tn(yn().m(function t(){var e,n,a,r,o,s,l,u,d,h,g,p,f,m,v,y,b,w,k,E,x,S,C,I,A,_,M,D,B,L,P,O,F=arguments;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(s=F.length>0&&void 0!==F[0]?F[0]:null,l=document.getElementById("transfer-name").value,u=(null===(e=document.getElementById("transfer-amount-type"))||void 0===e?void 0:e.value)||"fixed",d=parseFloat(document.getElementById("transfer-amount").value),h="fixed"!==u&&isNaN(d)?0:d,g=document.getElementById("transfer-frequency").value,p=parseInt(document.getElementById("recurring-transfer-from-account").value),f=parseInt(document.getElementById("recurring-transfer-to-account").value),m=document.getElementById("transfer-due-day").value?parseInt(document.getElementById("transfer-due-day").value):null,y=(null===(n=document.getElementById("transfer-start-date"))||void 0===n?void 0:n.value)||null,"one-time"!==g){t.n=2;break}if(y){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please enter the date the transfer is due")),t.a(2,!1);case 1:b=y.split("-").map(Number),w=fn(b,3),k=w[1],E=w[2],k&&E&&(m=E,v=k);case 2:if(["yearly","semi-annually","quarterly"].includes(g)&&(v=parseInt(null===(x=document.getElementById("transfer-due-month"))||void 0===x?void 0:x.value)||null),S=document.getElementById("transfer-description-pattern").value||null,C=null!==(a=document.getElementById("transfer-category"))&&void 0!==a&&a.value?parseInt(document.getElementById("transfer-category").value):null,I=this.getSelectedTagIds(),A=document.getElementById("transfer-notes").value||null,_=(null===(r=document.getElementById("transfer-create-transaction"))||void 0===r?void 0:r.checked)||!1,M=(null===(o=document.getElementById("transfer-transaction-date"))||void 0===o?void 0:o.value)||null,D=document.getElementById("transfer-auto-pay").checked,p&&!isNaN(p)){t.n=3;break}return(0,c.I9)((0,i.Tl)("budget","Please select a source account")),t.a(2,!1);case 3:if(f&&!isNaN(f)){t.n=4;break}return(0,c.I9)((0,i.Tl)("budget","Please select a destination account")),t.a(2,!1);case 4:if(p!==f){t.n=5;break}return(0,c.I9)((0,i.Tl)("budget","Cannot transfer to the same account")),t.a(2,!1);case 5:return B=gn(gn({name:l,amount:h,amountType:u,frequency:g,accountId:p,destinationAccountId:f,dueDay:m},void 0!==v?{dueMonth:v}:{}),{},{startDate:y,transferDescriptionPattern:S,categoryId:C,tagIds:I,notes:A,autoPayEnabled:D,isTransfer:!0}),s||(B.createTransaction=_,B.transactionDate=M),t.p=6,L=s?"/apps/budget/api/bills/".concat(s.id):"/apps/budget/api/bills",P=s?"PUT":"POST",t.n=7,(0,T.n)(L,{method:P,body:B,errorMessage:(0,i.Tl)("budget","Failed to save transfer")});case 7:return(0,c.Te)(s?(0,i.Tl)("budget","Transfer updated"):(0,i.Tl)("budget","Transfer added")),t.n=8,this.loadTransfers();case 8:return this.renderTransfers(),this.updateSummary(),t.a(2,!0);case 9:return t.p=9,O=t.v,console.error("Failed to save transfer:",O),(0,c.Qg)(O.message||(0,i.Tl)("budget","Failed to save transfer")),t.a(2,!1)}},t,this,[[6,9]])})),function(){return m.apply(this,arguments)})},{key:"deleteTransfer",value:(f=Tn(yn().m(function t(e){var n;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.n=1,(0,l.ZD)((0,i.Tl)("budget","Are you sure you want to delete this transfer?"),{destructive:!0});case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/bills/".concat(e),{method:"DELETE",errorMessage:(0,i.Tl)("budget","Failed to delete transfer")});case 3:return(0,c.Te)((0,i.Tl)("budget","Transfer deleted")),t.n=4,this.loadTransfers();case 4:this.renderTransfers(),this.updateSummary(),t.n=6;break;case 5:t.p=5,n=t.v,console.error("Failed to delete transfer:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to delete transfer"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(t){return f.apply(this,arguments)})},{key:"toggleTransferActive",value:(p=Tn(yn().m(function t(e){var n,a;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=this.transfers.find(function(t){return t.id===e})){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,(0,T.n)("/apps/budget/api/bills/".concat(e),{method:"PUT",body:{active:!n.isActive},errorMessage:(0,i.Tl)("budget","Failed to update transfer")});case 2:return(0,c.Te)(n.isActive?(0,i.Tl)("budget","Transfer deactivated"):(0,i.Tl)("budget","Transfer activated")),t.n=3,this.loadTransfers();case 3:this.renderTransfers(),this.updateSummary(),t.n=5;break;case 4:t.p=4,a=t.v,console.error("Failed to toggle transfer:",a),(0,c.Qg)((0,i.Tl)("budget","Failed to update transfer"));case 5:return t.a(2)}},t,this,[[1,4]])})),function(t){return p.apply(this,arguments)})},{key:"markTransferPaid",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return(0,ee.O)("bill-paid-".concat(t),n,function(){return e._markTransferPaid(t)})}},{key:"_markTransferPaid",value:(g=Tn(yn().m(function t(e){var n,a,r,s,l,u,d,h,g,p,f,m,v;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=this.transfers.find(function(t){return t.id===e})){t.n=1;break}return t.a(2);case 1:return t.p=1,r=n.nextDueDate||n.next_due_date||null,s=n.currency||(0,k.$S)(this.accounts,null!==(a=n.accountId)&&void 0!==a?a:n.account_id),t.n=2,(0,Ke.tf)(e,r,this.settings,{currency:s});case 2:if(null!==(l=t.v)){t.n=3;break}return t.a(2);case 3:if(u={action:"create"},!l.usePayment){t.n=4;break}u={action:"use",payment:l.usePayment},t.n=7;break;case 4:if(!n.accountId&&!n.account_id){t.n=7;break}return t.n=5,(0,T.n)("/apps/budget/api/bills/".concat(e,"/matching-transactions")).catch(function(){return null});case 5:if(d=t.v,!((h=d?(0,k.vy)(d,this.accounts):null)&&h.length>0)){t.n=7;break}return t.n=6,(0,cn.l)(n,h,this.settings);case 6:if(null!==(u=t.v)){t.n=7;break}return t.a(2);case 7:return g={recordPayment:"create"===u.action,dueDate:r},"link"===u.action?g.existingTransactionId=u.transactionId:"use"===u.action?g.paidDate=u.payment.date:g.paidDate=o.rT(),l.confirmSecondPayment&&(g.confirmSecondPayment=!0),t.n=8,(0,Ke.Fd)("/apps/budget/api/bills/".concat(e,"/paid"),g,this.settings,{currency:s,errorMessage:(0,i.Tl)("budget","Failed to mark transfer as paid")});case 8:if(null!==(p=t.v)){t.n=9;break}return t.a(2);case 9:return f=p.result,(m="use"===u.action?u.payment:p.usedPayment)?(0,c.Te)((0,i.Tl)("budget","Marked as paid with the payment of {date}",{date:o.Yq(m.date,this.settings)})):f&&!1===f.paymentTransactionRecorded?(0,c.I9)((0,i.Tl)("budget","The transfer was marked as paid, but no transactions were recorded. Check both accounts, or add the transfer manually.")):(0,c.Te)((0,i.Tl)("budget","Transfer marked as paid")),t.n=10,this.loadTransfers();case 10:this.renderTransfers(),this.updateSummary(),t.n=12;break;case 11:return t.p=11,v=t.v,console.error("Failed to mark transfer as paid:",v),(0,c.Qg)(v.message||(0,i.Tl)("budget","Failed to mark transfer as paid")),t.n=12,this._reloadAfterRefusal(v);case 12:return t.a(2)}},t,this,[[1,11]])})),function(t){return g.apply(this,arguments)})},{key:"_reloadAfterRefusal",value:(h=Tn(yn().m(function t(e){return yn().w(function(t){for(;;)switch(t.n){case 0:if(!(e instanceof T.h)){t.n=2;break}return t.n=1,this.loadTransfers();case 1:this.renderTransfers(),this.updateSummary();case 2:return t.a(2)}},t,this)})),function(t){return h.apply(this,arguments)})},{key:"skipTransfer",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return(0,ee.O)("bill-paid-".concat(t),n,function(){return e._skipTransfer(t)})}},{key:"_skipTransfer",value:(d=Tn(yn().m(function t(e){var n,a,r,o,s,u,d=this;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=this.transfers.find(function(t){return t.id===e})){t.n=1;break}return t.a(2);case 1:return t.n=2,(0,l.ZD)((0,i.Tl)("budget","Skip this payment and advance to the next due date?"));case 2:if(t.v){t.n=3;break}return t.a(2);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/bills/".concat(e,"/skip"),{method:"POST",body:{dueDate:n.nextDueDate||n.next_due_date||null},errorMessage:(0,i.Tl)("budget","Failed to skip transfer")});case 4:return r=t.v,o={transferId:e,previousNextDueDate:null!==(a=r.previousNextDueDate)&&void 0!==a?a:null,action:"skip"},this._undoData=o,t.n=5,this.loadTransfers();case 5:this.renderTransfers(),this.updateSummary(),s=(0,c.JC)((0,i.Tl)("budget","Payment skipped. Advanced to next due date."),function(){return d.undoSkipTransfer(o)},function(){(0,Qe.LB)(o),d._dropUndo(o)}),(0,Qe.to)(o,"transfer-".concat(e),o.previousNextDueDate,s),t.n=7;break;case 6:return t.p=6,u=t.v,console.error("Failed to skip transfer:",u),(0,c.Qg)(u.message||(0,i.Tl)("budget","Failed to skip transfer")),t.n=7,this._reloadAfterRefusal(u);case 7:return t.a(2)}},t,this,[[3,6]])})),function(t){return d.apply(this,arguments)})},{key:"_dropUndo",value:function(t){t.spent=!0,this._undoData===t&&(this._undoData=null)}},{key:"undoSkipTransfer",value:(r=Tn(yn().m(function t(){var e,n,a,r,o=arguments;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if((e=o.length>0&&void 0!==o[0]?o[0]:this._undoData)&&!e.spent&&"skip"===e.action){t.n=1;break}return t.a(2);case 1:return e.spent=!0,t.p=2,n=e.transferId,a=e.previousNextDueDate,t.n=3,(0,T.n)("/apps/budget/api/bills/".concat(n,"/undo-skip"),{method:"POST",body:{previousNextDueDate:a}});case 3:return(0,Qe.Ib)(e),this._undoData===e&&(this._undoData=null),t.n=4,this.loadTransfers();case 4:this.renderTransfers(),this.updateSummary(),(0,c.Te)((0,i.Tl)("budget","Action undone")),t.n=6;break;case 5:t.p=5,r=t.v,(0,Qe.LB)(e),console.error("Failed to undo skip:",r),(0,c.Qg)((0,i.Tl)("budget","Failed to undo action: {message}",{message:r.message}));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return r.apply(this,arguments)})},{key:"markTransferUnpaid",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return(0,ee.O)("bill-paid-".concat(t),n,function(){return e._markTransferUnpaid(t)})}},{key:"_markTransferUnpaid",value:(a=Tn(yn().m(function t(e){var n,a,r,o,s;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:return r=this.transfers.find(function(t){return t.id===e}),o=(0,ln.h)(r),!!r&&null!==(n=null!==(a=r.autoPayEnabled)&&void 0!==a?a:r.auto_pay_enabled)&&void 0!==n&&n&&(o+="\n\n"+(0,i.Tl)("budget","Auto-pay is on for this bill — it may pay it again on the next run. Disable auto-pay first if the payment should not recur.")),t.n=1,(0,l.ZD)(o,{destructive:!0});case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,(0,ln.E)(e,(0,i.Tl)("budget","Failed to mark transfer as unpaid"));case 3:if(t.v){t.n=4;break}return t.a(2);case 4:return t.n=5,this.loadTransfers();case 5:this.renderTransfers(),this.updateSummary(),(0,c.Te)((0,i.Tl)("budget","Payment reverted — the transfer is marked as unpaid.")),t.n=7;break;case 6:return t.p=6,s=t.v,console.error("Failed to mark transfer as unpaid:",s),(0,c.Qg)(s.message||(0,i.Tl)("budget","Failed to mark transfer as unpaid")),t.n=7,this._reloadAfterRefusal(s);case 7:return t.a(2)}},t,this,[[2,6]])})),function(t){return a.apply(this,arguments)})},{key:"amountTypeBadge",value:function(t){var e={statement:(0,i.Tl)("budget","Statement"),current_balance:(0,i.Tl)("budget","Full balance"),minimum_payment:(0,i.Tl)("budget","Minimum")};return e[t]?'').concat(e[t],""):""}},{key:"formatFrequency",value:function(t){return{weekly:(0,i.Tl)("budget","Weekly"),biweekly:(0,i.Tl)("budget","Bi-Weekly"),"semi-monthly":(0,i.Tl)("budget","Semi-Monthly"),monthly:(0,i.Tl)("budget","Monthly"),quarterly:(0,i.Tl)("budget","Quarterly"),"semi-annually":(0,i.Tl)("budget","Semi-Annually"),yearly:(0,i.Tl)("budget","Yearly"),"one-time":(0,i.Tl)("budget","One-Time")}[t]||t}},{key:"loadTransferTagSets",value:(n=Tn(yn().m(function t(e){var n,a,r,o,c,l,u,d,h,g,p,f,m,v=arguments;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(n=v.length>1&&void 0!==v[1]?v[1]:null,a=document.getElementById("transfer-tags-container")){t.n=1;break}return t.a(2);case 1:return t.p=1,o=e&&(!(null!==(r=this.categories)&&void 0!==r&&r.length)||this.categories.some(function(t){return String(t.id)===String(e)})),t.n=2,Promise.all([(0,T.n)("/apps/budget/api/tags/global").catch(function(){return[]}),o?(0,T.n)("/apps/budget/api/tag-sets?categoryId=".concat(e)).catch(function(){return[]}):Promise.resolve([])]);case 2:if(c=t.v,l=fn(c,2),u=l[0],d=l[1],h=(null==n?void 0:n.tagIds)||[],g=(0,ne.g)(u||[],h),p=(0,ne.s)(d||[],h),0!==g.length||0!==p.length){t.n=3;break}return a.innerHTML="",t.a(2);case 3:f="",g.length>0&&(f+='\n
\n \n
\n ').concat(g.map(function(t){return'\n \n ")}).join(""),"\n
\n
\n ")),p.forEach(function(t){f+='\n
\n \n
\n ').concat(t.tags&&t.tags.length>0?t.tags.map(function(e){return'\n \n ")}).join(""):''.concat((0,i.Tl)("budget","No tags defined"),""),"\n
\n
\n ")}),a.innerHTML=f,a.querySelectorAll(".transfer-tag-checkbox").forEach(function(t){t.addEventListener("change",function(t){var e=t.target.dataset.tagSetId;t.target.checked&&"global"!==e&&a.querySelectorAll('.transfer-tag-checkbox[data-tag-set-id="'.concat(e,'"]')).forEach(function(e){e!==t.target&&(e.checked=!1,e.closest(".tag-option").querySelector(".tag-badge").style.opacity="0.5")}),t.target.closest(".tag-option").querySelector(".tag-badge").style.opacity=t.target.checked?"1":"0.5"})}),t.n=5;break;case 4:t.p=4,m=t.v,console.error("Failed to load tag sets:",m),a.innerHTML="";case 5:return t.a(2)}},t,this,[[1,4]])})),function(t){return n.apply(this,arguments)})},{key:"getSelectedTagIds",value:function(){var t=document.getElementById("transfer-tags-container");return t?Array.from(t.querySelectorAll(".transfer-tag-checkbox:checked")).map(function(t){return parseInt(t.value)}):[]}},{key:"detectTransfers",value:(e=Tn(yn().m(function t(){var e,n;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.getElementById("detect-transfers-btn")){t.n=1;break}return t.a(2);case 1:return e.disabled=!0,e.innerHTML=' '.concat((0,i.Tl)("budget","Detecting...")),t.p=2,t.n=3,(0,T.n)("/apps/budget/api/bills/detect?months=6&transfers=true");case 3:if((n=t.v)&&0!==n.length){t.n=4;break}return(0,c.I9)((0,i.Tl)("budget","No recurring transactions detected")),t.a(2);case 4:this.renderDetectedTransfers(n),document.getElementById("detected-transfers-panel").style.display="flex",t.n=6;break;case 5:t.p=5,t.v,(0,c.Qg)((0,i.Tl)("budget","Failed to detect recurring transfers"));case 6:return t.p=6,e.disabled=!1,e.innerHTML=' '.concat((0,i.Tl)("budget","Find Transfers")),t.f(6);case 7:return t.a(2)}},t,this,[[2,5,6,7]])})),function(){return e.apply(this,arguments)})},{key:"renderDetectedTransfers",value:function(t){var e=this,n=document.getElementById("detected-transfers-list");if(n){var a=(0,k.HB)(this.accounts),r=a.map(function(t){return'")}).join("");n.innerHTML=t.map(function(t,n){var c=t.confidence>=.8?"high":t.confidence>=.5?"medium":"low",l=Math.round(100*t.confidence),u=a.find(function(e){return e.id===t.accountId}),d=u?u.name:(0,i.Tl)("budget","Unknown");return'\n
\n
\n =.7?"checked":"",'>\n
\n
\n \n
\n ').concat(o.vv(t.amount,(0,k.$S)(e.accounts,t.accountId),e.settings),'\n ').concat(t.frequency,'\n ').concat((0,i.Tl)("budget","{percent}% confidence",{percent:l}),"\n ").concat((0,i.Tl)("budget","From: {account}",{account:d}),'\n
\n
\n \n \n
\n
\n
\n ")}).join(""),t.forEach(function(t,e){var r=n.querySelector('.detected-dest-account[data-index="'.concat(e,'"]')),i=t.suggestedDestinationAccountId;r&&i&&a.some(function(t){return t.id===i})&&(r.value=String(i))}),this._detectedTransfers=t}}},{key:"addSelectedDetectedTransfers",value:function(){var t=this;return(0,ee.O)("transfers-add-detected",document.getElementById("add-detected-transfers-btn"),function(){return t._addSelectedDetectedTransfers()})}},{key:"_addSelectedDetectedTransfers",value:(t=Tn(yn().m(function t(){var e,n,a,r,o,s,l,u,d,h,g;return yn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.querySelectorAll('#detected-transfers-list input[type="checkbox"]:checked'),0!==(n=Array.from(e).map(function(t){return parseInt(t.id.replace("detected-transfer-",""))})).length){t.n=1;break}return(0,c.I9)((0,i.Tl)("budget","Please select at least one transfer to add")),t.a(2);case 1:a=[],r=dn(n),t.p=2,r.s();case 3:if((o=r.n()).done){t.n=7;break}if(s=o.value,l=document.querySelector('.detected-dest-account[data-index="'.concat(s,'"]')),u=l?parseInt(l.value):null){t.n=4;break}return(0,c.I9)((0,i.Tl)("budget","Please select a destination account for all selected transfers")),t.a(2);case 4:if(d=this._detectedTransfers[s],u!==d.accountId){t.n=5;break}return(0,c.I9)((0,i.Tl)("budget","Source and destination accounts must be different")),t.a(2);case 5:a.push(gn(gn({},d),{},{isTransfer:!0,destinationAccountId:u}));case 6:t.n=3;break;case 7:t.n=9;break;case 8:t.p=8,g=t.v,r.e(g);case 9:return t.p=9,r.f(),t.f(9);case 10:return t.p=10,t.n=11,(0,T.n)("/apps/budget/api/bills/create-from-detected",{method:"POST",body:{bills:a}});case 11:return h=t.v,document.getElementById("detected-transfers-panel").style.display="none",(0,c.Te)((0,i.zw)("budget","%n transfer added successfully","%n transfers added successfully",h.created)),t.n=12,this.loadTransfersView();case 12:t.n=14;break;case 13:t.p=13,t.v,(0,c.Qg)((0,i.Tl)("budget","Failed to add selected transfers"));case 14:return t.a(2)}},t,this,[[10,13],[2,8,9,10]])})),function(){return t.apply(this,arguments)})}]);var t,e,n,a,r,d,h,g,p,f,m,v,y,E,x}(),Sn=n(586),Cn="whats_new_seen";function In(t,e){for(var n=String(t).split(".").map(function(t){return parseInt(t,10)||0}),a=String(e).split(".").map(function(t){return parseInt(t,10)||0}),r=0;r0}).slice(0,3):[]}function Mn(t,e){return An(t,e).slice(0,3)}function Dn(){var t;return(null===(t=document.getElementById("app-content"))||void 0===t?void 0:t.dataset.appVersion)||""}const Bn=JSON.parse('[{"version":"3.3.0","title":"Calendar months in Category Details, and import and receipt fixes","items":["Category Details can show calendar months instead of budget periods.","CSV statements that leave empty cells off, such as Fortuneo\'s, now import every row.","Receipt scanning works with current Claude models.","Tags on a new transfer are saved, so savings goals count them.","Rules can add category tags."],"link":"https://github.com/otherworld-dev/Budget/blob/main/budget/CHANGELOG.md"},{"version":"3.2.0","title":"Category icons, receipt items sorted by your rules, and Monero","items":["Pick an icon for each category from about 60 in the category form.","Receipts split into items file each line under a category from your rules, and Remember saves a rule for next time.","Every amount box takes a decimal comma, such as 12,50, in any browser.","Monero (XMR) is in the currency list, with daily rates.","Repair Data can ignore a duplicate you have checked, so it stops coming back on every scan.","Category Details says when its bars are budget months rather than calendar months."],"link":"https://github.com/otherworld-dev/Budget/blob/main/budget/CHANGELOG.md"},{"version":"3.1.0","title":"Your own colours, and bills that are only paid once","items":["Pick the colours for money in and money out under Settings > Colours, including a colour-blind friendly preset. Amounts, budget bars, charts and PDF exports all follow them.","A transaction\'s menu has Link to bill, which files a payment you entered yourself under one of your bills, so it shows in Bills by Month.","Mark Paid asks before paying anything twice. When a bill already has a payment for its date you can use that payment, and a double click only counts once.","Bills by Month shows each payment in the month it was paid and the due date it paid, and counts a payment made either side of New Year once.","Importing a CSV again with the columns mapped differently no longer adds it a second time, even after you have edited a payee.","Repair Data finds more payments that older versions recorded twice.","The Transactions list keeps its headings and page controls in view, and works better on a laptop or a phone."],"link":"https://github.com/otherworld-dev/Budget/blob/main/budget/CHANGELOG.md"},{"version":"3.0.0","title":"Budget 3.0, the first release out of beta","items":["Budget is out of beta. 3.0 is the first release considered stable, every part of the app was reviewed and tested ahead of it, upgrading from 2.x included, so the beta warning has gone. Making a backup from Settings every now and then is still a good idea.","There is now an Android app, Budget Companion, on Google Play. Photograph a receipt and your own server reads it (when receipt scanning is set up), add a transaction by hand when there is no receipt, and check your balances, what is left of this month\'s budget and the bills due. Anything you enter without a signal is sent once you are back online.","An import folder: drop a bank statement into a folder in your Files and it is imported in the background, or held for you to check first. It is set up under Settings.","Statements can be imported straight from Excel and LibreOffice (.xls, .xlsx and .ods), and exports from Firefly III, YNAB, Actual Budget, Mint and Monarch Money can be brought across.","Sharing has a Full control level as well as Read only and Read & Write, and the Budget page has a Ready to Assign card, with weekly, quarterly and yearly budgets measured over the month.","The Transactions page works on a phone, the sidebar matches the rest of Nextcloud and the app opens faster.","Someone new to Budget gets a getting started checklist, and can try it out with sample data first."],"link":"https://github.com/otherworld-dev/Budget/blob/main/budget/CHANGELOG.md","links":[{"url":"https://play.google.com/store/apps/details?id=dev.otherworld.budget","text":"Get Budget Companion on Google Play"}]},{"version":"2.54.0","title":"Skipping transfers and a projected balance","items":["Transfers can now be skipped the same as bills, the due date moves on one cycle and Undo puts it back.","Pick an account in the Bills Calendar\'s Account filter and a Projected balance row shows what it should hold at the end of each month for the rest of the year.","Paid bills show the date they were paid as well as when they are next due.","A payment marked paid with no transaction behind it can be dismissed, rather than being listed for 60 days.","The import review warns about rows with no description, since import rules cannot categorise them."],"link":"https://github.com/otherworld-dev/Budget/blob/main/budget/CHANGELOG.md"}]');function Ln(t){return Ln="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Ln(t)}function Pn(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var a,r,i,o,s=[],c=!0,l=!1;try{if(i=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(a=i.call(n)).done)&&(s.push(a.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw r}}return s}}(t,e)||function(t,e){if(t){if("string"==typeof t)return On(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?On(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function On(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,a=Array(e);n3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(Rn(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,Rn(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,Rn(d,"constructor",l),Rn(l,"constructor",c),c.displayName="GeneratorFunction",Rn(l,r,"GeneratorFunction"),Rn(d),Rn(d,r,"Generator"),Rn(d,a,function(){return this}),Rn(d,"toString",function(){return"[object Generator]"}),(Fn=function(){return{w:i,m:h}})()}function Rn(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}Rn=function(t,e,n,a){function i(e,n){Rn(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},Rn(t,e,n,a)}function Nn(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function jn(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){Nn(i,a,r,o,s,"next",t)}function s(t){Nn(i,a,r,o,s,"throw",t)}o(void 0)})}}function Hn(t,e){for(var n=0;n0)){t.n=3;break}return t.n=3,(0,l.so)(r);case 3:return t.p=3,t.n=4,(0,T.n)("/apps/budget/api/settings/".concat(Cn),{method:"PUT",body:{value:n}});case 4:this.app.settings[Cn]=n,t.n=6;break;case 5:t.p=5,i=t.v,console.error("Failed to record the seen release notes:",i);case 6:return t.a(2)}},t,this,[[3,5]])})),function(){return e.apply(this,arguments)})},{key:"setupWhatsNewButton",value:function(){var t=document.getElementById("help-whats-new-btn");if(t){var e=Mn(Bn,Dn());t.style.display=0===e.length?"none":"",t.dataset.bound||(t.dataset.bound="1",t.addEventListener("click",function(){var t=Mn(Bn,Dn());t.length>0&&(0,l.so)(t)}))}}},{key:"renderDocLinks",value:function(){var t=document.getElementById("help-docs-grid");t&&(t.innerHTML=Object.entries(qn).filter(function(t){return"help"!==Pn(t,1)[0]}).map(function(t){var e=Pn(t,2)[1];return'\n \n ').concat(e.title(),'\n ').concat(e.summary(),"\n \n ")}).join(""))}},{key:"setupShortcutsButton",value:function(){var t=this,e=document.getElementById("help-view-shortcuts-btn");e&&!e.dataset.bound&&(e.dataset.bound="1",e.addEventListener("click",function(){return t.app.keyboardShortcuts.openShortcuts()}))}},{key:"setupReportIssueButton",value:function(){this.bindExternalLink("help-report-issue-btn","https://github.com/otherworld-dev/budget/issues"),this.bindExternalLink("help-docs-site-btn",Un),this.bindExternalLink("help-sponsor-github-btn",Gn),this.bindExternalLink("help-donate-paypal-btn",Zn)}},{key:"bindExternalLink",value:function(t,e){var n=document.getElementById(t);n&&!n.dataset.bound&&(n.dataset.bound="1",n.addEventListener("click",function(){return window.open(e,"_blank","noopener")}))}},{key:"setupQuickAddUrlCopy",value:function(){var t=document.getElementById("copy-quick-add-url"),e=document.getElementById("quick-add-url");t&&e&&!this.quickAddCopyBound&&(this.quickAddCopyBound=!0,t.addEventListener("click",function(){navigator.clipboard.writeText(e.value).then(function(){(0,c.Te)((0,i.Tl)("budget","URL copied to clipboard"))}).catch(function(){e.select(),document.execCommand("copy"),(0,c.Te)((0,i.Tl)("budget","URL copied to clipboard"))})}))}},{key:"loadSystemInfo",value:(t=jn(Fn().m(function t(){var e,n,a,r,o,l,u,d,h,g,p;return Fn().w(function(t){for(;;)switch(t.p=t.n){case 0:if(e=document.getElementById("system-info-content")){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,(0,T.n)("/apps/budget/api/setup/system-info",{errorMessage:"Failed to load"});case 2:a=t.v,r="".concat((null===(n=navigator.userAgent.match(/(?:Firefox|Chrome|Safari|Edge)\/[\d.]+/))||void 0===n?void 0:n[0])||navigator.userAgent.substring(0,50)),o=window.budgetDiagnostics||{errors:[],failedRequests:[]},l=[["Budget Version",a.appVersion],["Nextcloud Version",a.nextcloudVersion],["PHP Version",a.phpVersion],["Database",a.database],["Browser",r],["Accounts",a.accounts],["Transactions",a.transactions],["Categories",a.categories],["Rules","".concat(a.activeRules," active / ").concat(a.rules," total")],["Bills",a.bills],["Bank Sync",a.bankSyncConnections>0?"".concat(a.bankSyncConnections," connection(s)"):"None"],["Sharing",a.sharingOut>0||a.sharingIn>0?"".concat(a.sharingOut," outgoing, ").concat(a.sharingIn," incoming"):"None"],["Screen","".concat(window.screen.width,"x").concat(window.screen.height," (viewport: ").concat(window.innerWidth,"x").concat(window.innerHeight,")")]],u=''.concat(l.map(function(t){var e=Pn(t,2),n=e[0],a=e[1];return'")}).join(""),"
'.concat((0,s.ZD)(n),'').concat((0,s.ZD)(a),"
"),o.failedRequests.length>0&&(u+='

'.concat((0,i.Tl)("budget","Failed API Requests")," (").concat(o.failedRequests.length,")

"),u+='
'.concat(o.failedRequests.map(function(t){return'
'.concat((0,s.ZD)(t.time.substring(11,19))," ").concat((0,s.ZD)(t.method)," ").concat((0,s.ZD)(t.url)," → ").concat((0,s.ZD)(t.status),"
")}).join(""),"
")),o.errors.length>0&&(u+='

'.concat((0,i.Tl)("budget","JavaScript Errors")," (").concat(o.errors.length,")

"),u+='
'.concat(o.errors.map(function(t){return'
'.concat((0,s.ZD)(t.time.substring(11,19))," ").concat((0,s.ZD)(t.message)).concat(t.source?(0,s.ZD)(" ("+t.source+":"+t.line+")"):"","
")}).join(""),"
")),0===o.failedRequests.length&&(u+='

✔ '.concat((0,i.Tl)("budget","No failed API requests this session"),"

")),0===o.errors.length&&(u+='

✔ '.concat((0,i.Tl)("budget","No JavaScript errors this session"),"

")),a.serverLogs&&a.serverLogs.length>0?(d={0:"DEBUG",1:"INFO",2:"WARN",3:"ERROR",4:"FATAL"},u+='

'.concat((0,i.Tl)("budget","Server Logs (Budget)")," (").concat(a.serverLogs.length,")

"),u+='
'.concat(a.serverLogs.map(function(t){return'
').concat((0,s.ZD)(t.time.substring(11,19))," [").concat((0,s.ZD)(d[t.level]||t.level),"] ").concat((0,s.ZD)(t.message),"
")}).join(""),"
")):void 0!==a.serverLogs&&(u+='

✔ '.concat((0,i.Tl)("budget","No server errors logged"),"

")),e.innerHTML=u,h=l.map(function(t){var e=Pn(t,2),n=e[0],a=e[1];return"".concat(n,": ").concat(a)}).join("\n"),h+="\n\nFailed API Requests: "+(0===o.failedRequests.length?"None":o.failedRequests.length),o.failedRequests.length>0&&(h+="\n"+o.failedRequests.map(function(t){return" ".concat(t.time.substring(11,19)," ").concat(t.method," ").concat(t.url," → ").concat(t.status)}).join("\n")),h+="\nJavaScript Errors: "+(0===o.errors.length?"None":o.errors.length),o.errors.length>0&&(h+="\n"+o.errors.map(function(t){return" ".concat(t.time.substring(11,19)," ").concat(t.message).concat(t.source?" ("+t.source+":"+t.line+")":"")}).join("\n")),void 0!==a.serverLogs&&(g={0:"DEBUG",1:"INFO",2:"WARN",3:"ERROR",4:"FATAL"},h+="\nServer Logs: "+(0===a.serverLogs.length?"None":a.serverLogs.length),a.serverLogs.length>0&&(h+="\n"+a.serverLogs.map(function(t){return" ".concat(t.time.substring(11,19)," [").concat(g[t.level]||t.level,"] ").concat(t.message)}).join("\n"))),e.dataset.plaintext=h,(p=document.getElementById("copy-system-info-btn"))&&(p.onclick=function(){navigator.clipboard.writeText(e.dataset.plaintext).then(function(){(0,c.Te)((0,i.Tl)("budget","Copied to clipboard"))}).catch(function(){var t=document.createElement("textarea");t.value=e.dataset.plaintext,document.body.appendChild(t),t.select(),document.execCommand("copy"),t.remove(),(0,c.Te)((0,i.Tl)("budget","Copied to clipboard"))})}),t.n=4;break;case 3:t.p=3,t.v,e.innerHTML="

".concat((0,i.Tl)("budget","Failed to load system info"),"

");case 4:return t.a(2)}},t,null,[[1,3]])})),function(){return t.apply(this,arguments)})}]);var t,e}(),Qn=["leftAlone"];function $n(t,e,n){return(e=ra(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function Kn(t,e){if(null==t)return{};var n,a,r=function(t,e){if(null==t)return{};var n={};for(var a in t)if({}.hasOwnProperty.call(t,a)){if(-1!==e.indexOf(a))continue;n[a]=t[a]}return n}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(a=0;a3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(ta(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,ta(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,ta(d,"constructor",l),ta(l,"constructor",c),c.displayName="GeneratorFunction",ta(l,r,"GeneratorFunction"),ta(d),ta(d,r,"Generator"),ta(d,a,function(){return this}),ta(d,"toString",function(){return"[object Generator]"}),(Jn=function(){return{w:i,m:h}})()}function ta(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}ta=function(t,e,n,a){function i(e,n){ta(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},ta(t,e,n,a)}function ea(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function na(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){ea(i,a,r,o,s,"next",t)}function s(t){ea(i,a,r,o,s,"throw",t)}o(void 0)})}}function aa(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,a=Array(e);n0});if(0===e.length)return"";if(1===e.length){var n=ia(e[0],2),a=n[0],r=n[1];return(0,i.zw)("budget","{folder} already holds a file. It stays where it is: only files added from now on are imported.","{folder} already holds %n files. They stay where they are: only files added from now on are imported.",r,{folder:a},{escape:!1})}return(0,i.Tl)("budget","Files already in {folders} stay where they are: only files added from now on are imported.",{folders:e.map(function(t){return ia(t,1)[0]}).join(", ")},void 0,{escape:!1})}var da=function(){return function(t,e){return e&&aa(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t}(function t(e){var n=e.getAccounts;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.getAccounts=n,this.folders=[],this.templates=[],this.bound=!1},[{key:"load",value:(o=na(Jn().m(function t(){var e,n,a,r,i;return Jn().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,Promise.all([(0,T.n)(la),(0,T.n)("/apps/budget/api/import-templates")]);case 1:e=t.v,n=ia(e,2),a=n[0],r=n[1],this.folders=(null==a?void 0:a.folders)||[],this.templates=Array.isArray(r)?r:[],t.n=3;break;case 2:t.p=2,i=t.v,console.error("Failed to load import folders:",i),this.folders=[];case 3:this.fillPickers(),this.render(),this.bind();case 4:return t.a(2)}},t,this,[[0,2]])})),function(){return o.apply(this,arguments)})},{key:"refresh",value:(r=na(Jn().m(function t(){var e,n;return Jn().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,t.n=1,(0,T.n)(la);case 1:e=t.v,this.folders=(null==e?void 0:e.folders)||[],this.render(),t.n=3;break;case 2:t.p=2,n=t.v,console.error("Failed to reload import folders:",n);case 3:return t.a(2)}},t,this,[[0,2]])})),function(){return r.apply(this,arguments)})},{key:"accounts",value:function(t){return(0,k.FG)(this.getAccounts()||[],t?[t]:[])}},{key:"accountOptions",value:function(t,e){t.replaceChildren.apply(t,Xn(this.accounts(e).map(function(t){return new Option(t.name,String(t.id))}))),null!=e&&(t.value=String(e))}},{key:"modeOptions",value:function(t,e){t.replaceChildren(new Option((0,i.Tl)("budget","Import automatically"),"auto"),new Option((0,i.Tl)("budget","Hold for review"),"review")),t.value="review"===e?"review":"auto"}},{key:"templateOptions",value:function(t,e){t.replaceChildren.apply(t,[new Option((0,i.Tl)("budget","None (OFX, QIF and camt files only)"),"")].concat(Xn(this.templates.map(function(t){return new Option("".concat(t.name," (").concat(String(t.format||"csv").toUpperCase(),")"),String(t.id))})))),t.value=e?String(e):""}},{key:"fillPickers",value:function(){var t=document.getElementById("import-folder-account"),e=document.getElementById("import-folder-template");t&&this.accountOptions(t),e&&this.templateOptions(e)}},{key:"render",value:function(){var t=this,e=document.getElementById("import-folders-list"),n=document.getElementById("import-folders-table"),a=document.getElementById("import-folders-empty");e&&(e.replaceChildren.apply(e,Xn(this.folders.map(function(e){return t.row(e)}))),n&&(n.hidden=0===this.folders.length),a&&(a.hidden=this.folders.length>0))}},{key:"row",value:function(t){var e=document.createElement("tr");e.dataset.id=String(t.id);var n=document.createElement("th");n.scope="row",n.textContent=t.name;var a=document.createElement("select");a.dataset.field="accountId",a.setAttribute("aria-label",(0,i.Tl)("budget","Account for {folder}",{folder:t.name},void 0,{escape:!1})),this.accountOptions(a,t.accountId);var r=document.createElement("select");r.dataset.field="templateId",r.setAttribute("aria-label",(0,i.Tl)("budget","Import template for {folder}",{folder:t.name},void 0,{escape:!1})),this.templateOptions(r,t.templateId);var o=document.createElement("select");o.dataset.field="mode",o.setAttribute("aria-label",(0,i.Tl)("budget","When a file arrives in {folder}",{folder:t.name},void 0,{escape:!1})),this.modeOptions(o,t.mode);var s=document.createElement("input");s.type="checkbox",s.dataset.field="enabled",s.checked=!!t.enabled,s.setAttribute("aria-label",(0,i.Tl)("budget","Import files dropped into {folder}",{folder:t.name},void 0,{escape:!1}));var c=document.createElement("button");c.type="button",c.className="icon-delete",c.setAttribute("aria-label",(0,i.Tl)("budget","Remove {folder}",{folder:t.name},void 0,{escape:!1})),c.title=(0,i.Tl)("budget","Remove");for(var l=0,u=[n,a,r,o,s,c];l0&&u.push((0,i.zw)("budget","%n file imported","%n files imported",n)),l>0&&u.push((0,i.zw)("budget","%n file ready to review","%n files ready to review",l)),r>0&&u.push((0,i.zw)("budget","%n file could not be imported","%n files could not be imported",r)),s>0&&u.push((0,i.zw)("budget","%n file still uploading or waiting its turn","%n files still uploading or waiting their turn",s)),u.length?u.join(", "):(0,i.Tl)("budget","Nothing to import")}}]);var t,e,n,a,r,o}();function ha(t){return ha="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},ha(t)}function ga(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var a,r,i,o,s=[],c=!0,l=!1;try{if(i=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(a=i.call(n)).done)&&(s.push(a.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw r}}return s}}(t,e)||function(t,e){if(t){if("string"==typeof t)return pa(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?pa(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function pa(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,a=Array(e);n3?(r=p===a)&&(c=i[(s=i[4])?5:(s=3,3)],i[4]=i[5]=t):i[0]<=g&&((r=n<2&&ga||a>p)&&(i[4]=n,i[5]=a,h.n=p,s=0))}if(r||n>1)return o;throw d=!0,a}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(d&&1===u&&g(u,p),s=u,c=p;(e=s<2?t:c)||!d;){i||(s?s<3?(s>1&&(h.n=-1),g(s,c)):h.n=c:h.v=c);try{if(l=2,i){if(s||(r="next"),e=i[r]){if(!(e=e.call(i,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=i.return)&&e.call(i),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);i=t}else if((e=(d=h.n<0)?c:n.call(a,h))!==o)break}catch(e){i=t,s=1,c=e}finally{l=1}}return{value:e,done:d}}}(n,r,i),!0),l}var o={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][a]?e(e([][a]())):(ma(e={},a,function(){return this}),e),d=l.prototype=s.prototype=Object.create(u);function h(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,ma(t,r,"GeneratorFunction")),t.prototype=Object.create(d),t}return c.prototype=l,ma(d,"constructor",l),ma(l,"constructor",c),c.displayName="GeneratorFunction",ma(l,r,"GeneratorFunction"),ma(d),ma(d,r,"Generator"),ma(d,a,function(){return this}),ma(d,"toString",function(){return"[object Generator]"}),(fa=function(){return{w:i,m:h}})()}function ma(t,e,n,a){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}ma=function(t,e,n,a){function i(e,n){ma(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!a,configurable:!a,writable:!a}):t[e]=n:(i("next",0),i("throw",1),i("return",2))},ma(t,e,n,a)}function va(t,e,n,a,r,i,o){try{var s=t[i](o),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(a,r)}function ya(t){return function(){var e=this,n=arguments;return new Promise(function(a,r){var i=t.apply(e,n);function o(t){va(i,a,r,o,s,"next",t)}function s(t){va(i,a,r,o,s,"throw",t)}o(void 0)})}}function ba(t,e){for(var n=0;n0&&void 0!==g[0]?g[0]:null)||{provider:document.getElementById("setting-ocr-provider").value,endpoint:document.getElementById("setting-ocr-endpoint").value.trim(),model:document.getElementById("setting-ocr-model").value.trim()},e||""!==(a=document.getElementById("setting-ocr-api-key").value).trim()&&(n.apiKey=a),t.p=1,t.n=2,(0,T.n)("/apps/budget/api/admin/settings",{method:"PUT",body:{ocr:n},errorMessage:(0,i.Tl)("budget","Failed to save admin settings")});case 2:d=t.v,this.ocrState={apiKeySet:!(null===(r=d.ocr)||void 0===r||!r.apiKeySet),nextcloudAiAvailable:!(null===(o=d.ocr)||void 0===o||!o.nextcloudAiAvailable),relayBillingBase:(null===(s=d.ocr)||void 0===s?void 0:s.relayBillingBase)||(null===(l=this.ocrState)||void 0===l?void 0:l.relayBillingBase)||"https://api.otherworld.dev/billing"},document.getElementById("setting-ocr-api-key").value="",this.renderOcrFields(),(0,c.Te)(null!==(u=d.ocr)&&void 0!==u&&u.configured?(0,i.Tl)("budget","Receipt scanning is on"):(0,i.Tl)("budget","Receipt scanning settings saved")),t.n=4;break;case 3:t.p=3,h=t.v,(0,c.Qg)(h.message||(0,i.Tl)("budget","Failed to save admin settings"));case 4:return t.a(2)}},t,this,[[1,3]])})),function(){return s.apply(this,arguments)})},{key:"populateSettings",value:(o=ya(fa().m(function t(e){return fa().w(function(t){for(;;)switch(t.n){case 0:Object.keys(e).forEach(function(t){var n=document.getElementById("setting-".concat(t.replace(/_/g,"-")));if(n){var a=e[t];"checkbox"===n.type?n.checked="true"===a||!0===a:n.value=a}}),this.syncAmountColourControls();case 1:return t.a(2)}},t,this)})),function(t){return o.apply(this,arguments)})},{key:"setupFolderPicker",value:function(t,e,n,a){var r=document.getElementById(t),i=document.getElementById(e);r&&i&&!r.dataset.bound&&(r.dataset.bound="1",r.addEventListener("click",function(){var t=i.value.trim()||a;OC.dialogs.filepicker(n,function(t){i.value=String(t||"").replace(/^\/+|\/+$/g,""),i.dispatchEvent(new Event("change",{bubbles:!0}))},!1,"httpd/unix-directory",!0,OC.dialogs.FILEPICKER_TYPE_CHOOSE,"/"+t)}))}},{key:"setupReceiptFolderPicker",value:function(){this.setupFolderPicker("setting-receipt-folder-browse","setting-receipt-folder",(0,i.Tl)("budget","Select receipts folder"),"Budget/Receipts")}},{key:"setupImportFolderPicker",value:function(){this.setupFolderPicker("setting-import-folder-browse","setting-import-folder",(0,i.Tl)("budget","Select import folder"),"Budget/Import")}},{key:"setupAutoSave",value:function(){var e=this,n=document.getElementById("settings-view");n&&!n.dataset.autosaveBound&&(n.dataset.autosaveBound="1",n.addEventListener("change",function(n){if(n.target.closest(".amount-color-picker"))e.onAmountColourPickerChange();else{var a=n.target.closest(".setting-input");a&&(t.PREVIEW_INPUTS.includes(a.id)&&e.updateNumberFormatPreview(),"setting-amount-color-scheme"===a.id&&e.syncAmountColourControls(),e.saveSetting(a))}}),n.addEventListener("input",function(t){t.target.closest(".amount-color-picker")&&(e.updateAmountColourPreview(),e.updateAmountColourWarnings())}))}},{key:"setupJumpList",value:function(){var t=document.querySelector(".settings-jump");t&&!t.dataset.bound&&(t.dataset.bound="1",t.addEventListener("click",function(t){var e=t.target.closest("button[data-target]"),n=e&&document.getElementById(e.dataset.target);if(n){n.scrollIntoView({behavior:"smooth",block:"start"});var a=n.querySelector("h3");a&&(a.setAttribute("tabindex","-1"),a.focus({preventScroll:!0}))}}))}},{key:"settingEntry",value:function(t){return[t.id.replace("setting-","").replace(/-/g,"_"),"checkbox"===t.type?t.checked?"true":"false":t.value]}},{key:"saveSetting",value:function(t){var e=this,n=ga(this.settingEntry(t),1)[0];this.savesInFlight=this.savesInFlight||{};var a=this.savesInFlight[n];if(a)return a.element=t,a.again=!0,a.promise;var r={element:t,again:!1};return this.savesInFlight[n]=r,r.promise=ya(fa().m(function t(){var a,i,o,s,c;return fa().w(function(t){for(;;)switch(t.p=t.n){case 0:t.p=0,a=!0;case 1:if(!a&&!r.again){t.n=4;break}if(o=e.settingEntry(r.element),s=ga(o,2),c=s[1],a||c!==String(null===(i=e.settings)||void 0===i?void 0:i[n])){t.n=2;break}return t.a(3,4);case 2:return a=!1,r.again=!1,t.n=3,e.sendSetting(r.element,r);case 3:t.n=1;break;case 4:return t.p=4,delete e.savesInFlight[n],t.f(4);case 5:return t.a(2)}},t,null,[[0,,4,5]])}))(),r.promise}},{key:"sendSetting",value:(r=ya(fa().m(function t(e,n){var a,r,o,s,l,u,d,h,g,p,f,m,v;return fa().w(function(t){for(;;)switch(t.p=t.n){case 0:return a=this.settingEntry(e),r=ga(a,2),o=r[0],s=r[1],l=e.closest(".setting-item")||e.parentElement,t.p=1,t.n=2,(0,T.n)("/apps/budget/api/settings",{method:"PUT",body:wa({},o,s),errorMessage:(0,i.Tl)("budget","Failed to save settings")});case 2:h=t.v,g=null!==(u=null==h||null===(d=h.settings)||void 0===d?void 0:d[o])&&void 0!==u?u:s,n.again||"checkbox"===e.type||g===s||(e.value=g),this.settings[o]=g,this.applySettingSideEffects(wa({},o,g)),this.flashSaved(l),(p="import_folder"===o?ua(null==h?void 0:h.importFolderLeftAlone):"")&&(0,c.cf)(p),t.n=5;break;case 3:if(t.p=3,v=t.v,console.error("Error saving setting:",o,v),(0,c.Qg)(v.message||(0,i.Tl)("budget","Failed to save settings")),!n.again){t.n=4;break}return t.a(2);case 4:void 0!==(m=null===(f=this.settings)||void 0===f?void 0:f[o])&&("checkbox"===e.type?e.checked="true"===m||!0===m:e.value=m,"amount_color_custom"===o&&this.syncAmountColourControls());case 5:return t.a(2)}},t,this,[[1,3]])})),function(t,e){return r.apply(this,arguments)})},{key:"applySettingSideEffects",value:function(t){this.updateAccountFormDefaults(t),("amount_color_scheme"in t||"amount_color_custom"in t)&&(0,g.ET)(this.settings.amount_color_scheme,this.settings.amount_color_custom),("date_format"in t||"first_day_of_week"in t)&&(0,u.c6)(this.app.settings)}},{key:"flashSaved",value:function(t){if(t){var e=t.querySelector(":scope > .setting-saved");e||((e=document.createElement("span")).className="setting-saved",e.setAttribute("role","status"),t.appendChild(e)),e.textContent=(0,i.Tl)("budget","Saved"),e.classList.add("visible"),clearTimeout(e._timer),e._timer=setTimeout(function(){return e.classList.remove("visible")},2e3)}}},{key:"saveSettings",value:(a=ya(fa().m(function t(){var e,n;return fa().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.p=0,e=this.gatherSettings(),t.n=1,(0,T.n)("/apps/budget/api/settings",{method:"PUT",body:e});case 1:(0,c.Te)((0,i.Tl)("budget","Settings saved successfully")),Object.assign(this.settings,e),this.updateAccountFormDefaults(e),(0,u.c6)(this.app.settings),this.app.reloadCurrentView&&this.app.reloadCurrentView(),t.n=3;break;case 2:t.p=2,n=t.v,console.error("Error saving settings:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to save settings"));case 3:return t.a(2)}},t,this,[[0,2]])})),function(){return a.apply(this,arguments)})},{key:"gatherSettings",value:function(){var t=document.querySelectorAll(".setting-input"),e={};return t.forEach(function(t){var n=t.id.replace("setting-","").replace(/-/g,"_");"checkbox"===t.type?e[n]=t.checked?"true":"false":e[n]=t.value}),e}},{key:"resetSettings",value:(n=ya(fa().m(function t(){var e,n;return fa().w(function(t){for(;;)switch(t.p=t.n){case 0:return t.n=1,(0,l.ZD)((0,i.Tl)("budget","Are you sure you want to reset all settings to defaults? This action cannot be undone."),{destructive:!0});case 1:if(t.v){t.n=2;break}return t.a(2);case 2:return t.p=2,t.n=3,(0,T.n)("/apps/budget/api/settings/reset",{method:"POST"});case 3:return e=t.v,t.n=4,this.populateSettings(e.defaults);case 4:Object.assign(this.settings,e.defaults),this.applySettingSideEffects(e.defaults),this.updateNumberFormatPreview(),(0,c.Te)((0,i.Tl)("budget","Settings reset to defaults")),t.n=6;break;case 5:t.p=5,n=t.v,console.error("Error resetting settings:",n),(0,c.Qg)((0,i.Tl)("budget","Failed to reset settings"));case 6:return t.a(2)}},t,this,[[2,5]])})),function(){return n.apply(this,arguments)})},{key:"updateNumberFormatPreview",value:function(){var t,e,n,a,r,i=parseInt((null===(t=document.getElementById("setting-number-format-decimals"))||void 0===t?void 0:t.value)||"2"),o=(null===(e=document.getElementById("setting-number-format-decimal-sep"))||void 0===e?void 0:e.value)||".",s=null!==(n=null===(a=document.getElementById("setting-number-format-thousands-sep"))||void 0===a?void 0:a.value)&&void 0!==n?n:",",c={USD:"$",CAD:"C$",MXN:"MX$",BRL:"R$",ARS:"AR$",CLP:"CL$",COP:"CO$",PEN:"S/",EUR:"€",GBP:"£",CHF:"CHF",SEK:"kr",NOK:"kr",DKK:"kr",PLN:"zł",CZK:"Kč",HUF:"Ft",RON:"lei",UAH:"₴",ISK:"kr",RUB:"₽",BYN:"Br",TRY:"₺",JPY:"¥",CNY:"¥",KRW:"₩",INR:"₹",IDR:"Rp",THB:"฿",PHP:"₱",MYR:"RM",VND:"₫",TWD:"NT$",SGD:"S$",HKD:"HK$",PKR:"Rs",BDT:"৳",AUD:"A$",NZD:"NZ$",AED:"AED",SAR:"SAR",QAR:"QAR",JOD:"JOD",ILS:"₪",EGP:"E£",NGN:"₦",KES:"KSh",ZAR:"R"}[(null===(r=document.getElementById("setting-default-currency"))||void 0===r?void 0:r.value)||"USD"]||"$",l=1234.56.toFixed(i).split("."),u=c+l[0].replace(/\B(?=(\d{3})+(?!\d))/g,s)+(i>0?o+l[1]:""),d=document.getElementById("number-format-preview");d&&(d.textContent=u)}},{key:"readAmountColourPickers",value:function(){for(var e={},n=0,a=Object.entries(t.AMOUNT_COLOUR_PICKERS);n