@harbortouch/skytab-analytics-report-utils 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,6 +19,10 @@ export interface FormatMoneyOptions {
19
19
  currency?: string;
20
20
  decimals?: number;
21
21
  }
22
+ export interface FormatNumberOptions {
23
+ locale?: string;
24
+ decimals?: number;
25
+ }
22
26
  export declare const formatDate: (date: Date, options?: FormatDateOptions) => string;
23
27
  export declare const formatTime: (date: Date | string | number, options: FormatTimeOptions) => string;
24
28
  export declare const formatMoney: (amount: number, options?: FormatMoneyOptions) => string;
@@ -28,7 +32,7 @@ export declare const formatFixedNumber: (value: number, decimals?: number) => st
28
32
  export declare const formatString: (value: unknown) => string;
29
33
  export declare const getNumberToFormat: (value: unknown) => number;
30
34
  export declare const getDateToFormat: (value?: unknown) => Date | null;
31
- export declare const formatMoneyWithoutSymbol: (amount: number, options?: FormatMoneyOptions) => string;
35
+ export declare const formatMoneyWithoutSymbol: (amount: number, options?: FormatNumberOptions) => string;
32
36
  export declare const getReportFormattingLocaleOptions: (locations: {
33
37
  currency: string;
34
38
  countryCode: string;
package/dist/index.cjs CHANGED
@@ -1525,8 +1525,12 @@ function calculateReportTotals(data, fieldConfig, opts) {
1525
1525
  }
1526
1526
  } else {
1527
1527
  derivedFields.push({ field, calc });
1528
- if (calc.numeratorField) fieldsToSum.add(calc.numeratorField);
1529
- if (calc.denominatorField) fieldsToSum.add(calc.denominatorField);
1528
+ if (calc.numeratorField) {
1529
+ fieldsToSum.add(calc.numeratorField);
1530
+ }
1531
+ if (calc.denominatorField) {
1532
+ fieldsToSum.add(calc.denominatorField);
1533
+ }
1530
1534
  }
1531
1535
  }
1532
1536
  const sums = {};
@@ -1605,48 +1609,75 @@ var dailySalesTaxesConfig = {
1605
1609
  };
1606
1610
 
1607
1611
  // src/formatting.ts
1612
+ var dateFormatterCache = /* @__PURE__ */ new Map();
1613
+ var timeFormatterCache = /* @__PURE__ */ new Map();
1614
+ var moneyFormatterCache = /* @__PURE__ */ new Map();
1615
+ var numberFormatterCache = /* @__PURE__ */ new Map();
1616
+ var getDateFormatter = (locale, timeZone) => {
1617
+ const key = `${locale}-${timeZone}`;
1618
+ let fmt = dateFormatterCache.get(key);
1619
+ if (!fmt) {
1620
+ fmt = new Intl.DateTimeFormat(locale, { dateStyle: "short", timeZone });
1621
+ dateFormatterCache.set(key, fmt);
1622
+ }
1623
+ return fmt;
1624
+ };
1625
+ var getTimeFormatter = (locale, timeZone, format) => {
1626
+ const key = `${locale}-${timeZone}-${format}`;
1627
+ let fmt = timeFormatterCache.get(key);
1628
+ if (!fmt) {
1629
+ if (format === "00:00") {
1630
+ fmt = new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", timeZone });
1631
+ } else if (format === "00:00-24H") {
1632
+ fmt = new Intl.DateTimeFormat(locale, {
1633
+ hour: "2-digit",
1634
+ minute: "2-digit",
1635
+ hour12: false,
1636
+ hourCycle: "h23",
1637
+ timeZone
1638
+ });
1639
+ } else {
1640
+ fmt = new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", second: "2-digit", timeZone });
1641
+ }
1642
+ timeFormatterCache.set(key, fmt);
1643
+ }
1644
+ return fmt;
1645
+ };
1646
+ var getMoneyFormatter = (locale, currency, decimals) => {
1647
+ const key = `${locale}-${currency}-${decimals}`;
1648
+ let fmt = moneyFormatterCache.get(key);
1649
+ if (!fmt) {
1650
+ fmt = new Intl.NumberFormat(locale, {
1651
+ style: "currency",
1652
+ currency,
1653
+ minimumFractionDigits: decimals,
1654
+ maximumFractionDigits: decimals
1655
+ });
1656
+ moneyFormatterCache.set(key, fmt);
1657
+ }
1658
+ return fmt;
1659
+ };
1660
+ var getNumberFormatter = (locale, decimals) => {
1661
+ const key = `${locale}-${decimals}`;
1662
+ let fmt = numberFormatterCache.get(key);
1663
+ if (!fmt) {
1664
+ fmt = new Intl.NumberFormat(locale, { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
1665
+ numberFormatterCache.set(key, fmt);
1666
+ }
1667
+ return fmt;
1668
+ };
1608
1669
  var formatDate = (date, options = {}) => {
1609
1670
  const { locale = "en-US", timeZone = "UTC" } = options;
1610
- const d = new Date(date);
1611
- return new Intl.DateTimeFormat(locale, {
1612
- dateStyle: "short",
1613
- timeZone
1614
- }).format(d);
1671
+ return getDateFormatter(locale, timeZone).format(date);
1615
1672
  };
1616
1673
  var formatTime = (date, options) => {
1617
1674
  const { locale = "en-US", timeZone = "UTC", format } = options;
1618
1675
  const d = new Date(date);
1619
- if (format === "00:00") {
1620
- return new Intl.DateTimeFormat(locale, {
1621
- hour: "2-digit",
1622
- minute: "2-digit",
1623
- timeZone
1624
- }).format(d);
1625
- }
1626
- if (format === "00:00-24H") {
1627
- return new Intl.DateTimeFormat(locale, {
1628
- hour: "2-digit",
1629
- minute: "2-digit",
1630
- hour12: false,
1631
- hourCycle: "h23",
1632
- timeZone
1633
- }).format(d);
1634
- }
1635
- return new Intl.DateTimeFormat(locale, {
1636
- hour: "2-digit",
1637
- minute: "2-digit",
1638
- second: "2-digit",
1639
- timeZone
1640
- }).format(d);
1676
+ return getTimeFormatter(locale, timeZone, format).format(d);
1641
1677
  };
1642
1678
  var formatMoney = (amount, options = {}) => {
1643
1679
  const { locale = "en-US", currency = "USD", decimals = 2 } = options;
1644
- return new Intl.NumberFormat(locale, {
1645
- style: "currency",
1646
- currency,
1647
- minimumFractionDigits: decimals,
1648
- maximumFractionDigits: decimals
1649
- }).format(amount);
1680
+ return getMoneyFormatter(locale, currency, decimals).format(amount);
1650
1681
  };
1651
1682
  var formatPercent = (value, decimals = 2) => `${value.toFixed(decimals)}%`;
1652
1683
  var formatInteger = (value) => Math.round(value).toString();
@@ -1667,10 +1698,7 @@ var getDateToFormat = (value) => {
1667
1698
  };
1668
1699
  var formatMoneyWithoutSymbol = (amount, options = {}) => {
1669
1700
  const { locale = "en-US", decimals = 2 } = options;
1670
- return new Intl.NumberFormat(locale, {
1671
- minimumFractionDigits: decimals,
1672
- maximumFractionDigits: decimals
1673
- }).format(amount);
1701
+ return getNumberFormatter(locale, decimals).format(amount);
1674
1702
  };
1675
1703
  var getReportFormattingLocaleOptions = (locations) => {
1676
1704
  if (locations.length === 0) {
package/dist/index.d.ts CHANGED
@@ -17,5 +17,5 @@ export { dailySalesRefundsVoidsConfig, DAILY_SALES_REFUNDS_VOIDS_AVAILABLE_COLUM
17
17
  export { dailySalesTaxesConfig, DAILY_SALES_TAXES_AVAILABLE_COLUMNS, DAILY_SALES_TAXES_DEFAULT_VISIBLE_COLUMNS, } from './reports/dailySalesTaxes';
18
18
  export { employeeTimecardConfig, EMPLOYEE_TIMECARD_AVAILABLE_COLUMNS, EMPLOYEE_TIMECARD_DEFAULT_VISIBLE_COLUMNS, } from './reports/employeeTimecard';
19
19
  export { salesByItemDetailConfig, SALES_BY_ITEM_DETAIL_AVAILABLE_COLUMNS, SALES_BY_ITEM_DETAIL_DEFAULT_VISIBLE_COLUMNS, } from './reports/salesByItemDetail';
20
- export type { FormatDateOptions, FormatTimeOptions, FormatMoneyOptions, LocaleOption, TimeFormat } from './formatting';
20
+ export type { FormatNumberOptions, FormatDateOptions, FormatTimeOptions, FormatMoneyOptions, LocaleOption, TimeFormat, } from './formatting';
21
21
  export { formatDate, formatTime, formatMoney, formatPercent, formatInteger, formatFixedNumber, formatString, getNumberToFormat, getDateToFormat, getReportFormattingLocaleOptions, formatMoneyWithoutSymbol, formatFieldValue, } from './formatting';
package/dist/index.js CHANGED
@@ -1437,8 +1437,12 @@ function calculateReportTotals(data, fieldConfig, opts) {
1437
1437
  }
1438
1438
  } else {
1439
1439
  derivedFields.push({ field, calc });
1440
- if (calc.numeratorField) fieldsToSum.add(calc.numeratorField);
1441
- if (calc.denominatorField) fieldsToSum.add(calc.denominatorField);
1440
+ if (calc.numeratorField) {
1441
+ fieldsToSum.add(calc.numeratorField);
1442
+ }
1443
+ if (calc.denominatorField) {
1444
+ fieldsToSum.add(calc.denominatorField);
1445
+ }
1442
1446
  }
1443
1447
  }
1444
1448
  const sums = {};
@@ -1517,48 +1521,75 @@ var dailySalesTaxesConfig = {
1517
1521
  };
1518
1522
 
1519
1523
  // src/formatting.ts
1524
+ var dateFormatterCache = /* @__PURE__ */ new Map();
1525
+ var timeFormatterCache = /* @__PURE__ */ new Map();
1526
+ var moneyFormatterCache = /* @__PURE__ */ new Map();
1527
+ var numberFormatterCache = /* @__PURE__ */ new Map();
1528
+ var getDateFormatter = (locale, timeZone) => {
1529
+ const key = `${locale}-${timeZone}`;
1530
+ let fmt = dateFormatterCache.get(key);
1531
+ if (!fmt) {
1532
+ fmt = new Intl.DateTimeFormat(locale, { dateStyle: "short", timeZone });
1533
+ dateFormatterCache.set(key, fmt);
1534
+ }
1535
+ return fmt;
1536
+ };
1537
+ var getTimeFormatter = (locale, timeZone, format) => {
1538
+ const key = `${locale}-${timeZone}-${format}`;
1539
+ let fmt = timeFormatterCache.get(key);
1540
+ if (!fmt) {
1541
+ if (format === "00:00") {
1542
+ fmt = new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", timeZone });
1543
+ } else if (format === "00:00-24H") {
1544
+ fmt = new Intl.DateTimeFormat(locale, {
1545
+ hour: "2-digit",
1546
+ minute: "2-digit",
1547
+ hour12: false,
1548
+ hourCycle: "h23",
1549
+ timeZone
1550
+ });
1551
+ } else {
1552
+ fmt = new Intl.DateTimeFormat(locale, { hour: "2-digit", minute: "2-digit", second: "2-digit", timeZone });
1553
+ }
1554
+ timeFormatterCache.set(key, fmt);
1555
+ }
1556
+ return fmt;
1557
+ };
1558
+ var getMoneyFormatter = (locale, currency, decimals) => {
1559
+ const key = `${locale}-${currency}-${decimals}`;
1560
+ let fmt = moneyFormatterCache.get(key);
1561
+ if (!fmt) {
1562
+ fmt = new Intl.NumberFormat(locale, {
1563
+ style: "currency",
1564
+ currency,
1565
+ minimumFractionDigits: decimals,
1566
+ maximumFractionDigits: decimals
1567
+ });
1568
+ moneyFormatterCache.set(key, fmt);
1569
+ }
1570
+ return fmt;
1571
+ };
1572
+ var getNumberFormatter = (locale, decimals) => {
1573
+ const key = `${locale}-${decimals}`;
1574
+ let fmt = numberFormatterCache.get(key);
1575
+ if (!fmt) {
1576
+ fmt = new Intl.NumberFormat(locale, { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
1577
+ numberFormatterCache.set(key, fmt);
1578
+ }
1579
+ return fmt;
1580
+ };
1520
1581
  var formatDate = (date, options = {}) => {
1521
1582
  const { locale = "en-US", timeZone = "UTC" } = options;
1522
- const d = new Date(date);
1523
- return new Intl.DateTimeFormat(locale, {
1524
- dateStyle: "short",
1525
- timeZone
1526
- }).format(d);
1583
+ return getDateFormatter(locale, timeZone).format(date);
1527
1584
  };
1528
1585
  var formatTime = (date, options) => {
1529
1586
  const { locale = "en-US", timeZone = "UTC", format } = options;
1530
1587
  const d = new Date(date);
1531
- if (format === "00:00") {
1532
- return new Intl.DateTimeFormat(locale, {
1533
- hour: "2-digit",
1534
- minute: "2-digit",
1535
- timeZone
1536
- }).format(d);
1537
- }
1538
- if (format === "00:00-24H") {
1539
- return new Intl.DateTimeFormat(locale, {
1540
- hour: "2-digit",
1541
- minute: "2-digit",
1542
- hour12: false,
1543
- hourCycle: "h23",
1544
- timeZone
1545
- }).format(d);
1546
- }
1547
- return new Intl.DateTimeFormat(locale, {
1548
- hour: "2-digit",
1549
- minute: "2-digit",
1550
- second: "2-digit",
1551
- timeZone
1552
- }).format(d);
1588
+ return getTimeFormatter(locale, timeZone, format).format(d);
1553
1589
  };
1554
1590
  var formatMoney = (amount, options = {}) => {
1555
1591
  const { locale = "en-US", currency = "USD", decimals = 2 } = options;
1556
- return new Intl.NumberFormat(locale, {
1557
- style: "currency",
1558
- currency,
1559
- minimumFractionDigits: decimals,
1560
- maximumFractionDigits: decimals
1561
- }).format(amount);
1592
+ return getMoneyFormatter(locale, currency, decimals).format(amount);
1562
1593
  };
1563
1594
  var formatPercent = (value, decimals = 2) => `${value.toFixed(decimals)}%`;
1564
1595
  var formatInteger = (value) => Math.round(value).toString();
@@ -1579,10 +1610,7 @@ var getDateToFormat = (value) => {
1579
1610
  };
1580
1611
  var formatMoneyWithoutSymbol = (amount, options = {}) => {
1581
1612
  const { locale = "en-US", decimals = 2 } = options;
1582
- return new Intl.NumberFormat(locale, {
1583
- minimumFractionDigits: decimals,
1584
- maximumFractionDigits: decimals
1585
- }).format(amount);
1613
+ return getNumberFormatter(locale, decimals).format(amount);
1586
1614
  };
1587
1615
  var getReportFormattingLocaleOptions = (locations) => {
1588
1616
  if (locations.length === 0) {
@@ -1,4 +1,6 @@
1
1
  import { type ReportConfig } from '../types';
2
- export declare const EMPLOYEE_TIMECARD_AVAILABLE_COLUMNS: string[];
3
- export declare const EMPLOYEE_TIMECARD_DEFAULT_VISIBLE_COLUMNS: string[];
4
- export declare const employeeTimecardConfig: ReportConfig;
2
+ type EmployeeTimecardField = 'locationId' | 'locationName' | 'businessDate' | 'employeeName' | 'isActive' | 'lookup' | 'payrollCode' | 'jobName' | 'isBreak' | 'startTime' | 'endTime' | 'shiftHours';
3
+ export declare const EMPLOYEE_TIMECARD_AVAILABLE_COLUMNS: EmployeeTimecardField[];
4
+ export declare const EMPLOYEE_TIMECARD_DEFAULT_VISIBLE_COLUMNS: EmployeeTimecardField[];
5
+ export declare const employeeTimecardConfig: ReportConfig<EmployeeTimecardField>;
6
+ export {};
package/dist/types.d.ts CHANGED
@@ -2,18 +2,18 @@ import { type ReportColumnKey } from './columns';
2
2
  export type FieldType = 'string' | 'money' | 'percent' | 'number' | 'fixedNumber' | 'date' | 'time' | 'boolean';
3
3
  export type ColumnAlignment = 'left' | 'right';
4
4
  export type FooterCalculationType = 'sum' | 'percentChange' | 'average' | 'none';
5
- export interface FooterCalculation {
5
+ export interface FooterCalculation<TField = string> {
6
6
  type: FooterCalculationType;
7
- numeratorField?: string;
8
- denominatorField?: string;
7
+ numeratorField?: TField;
8
+ denominatorField?: TField;
9
9
  }
10
- export interface ColumnPresentationConfig {
10
+ export interface ColumnPresentationConfig<TField = string> {
11
11
  columnKey?: ReportColumnKey;
12
- type?: FieldType;
12
+ type: FieldType;
13
13
  size?: number;
14
14
  enableSorting?: boolean;
15
15
  filteringAvailable?: boolean;
16
- footerCalculation?: FooterCalculation;
16
+ footerCalculation?: FooterCalculation<TField>;
17
17
  }
18
18
  export interface ColumnGroupConfig {
19
19
  id: string;
@@ -23,7 +23,7 @@ export interface ColumnGroupConfig {
23
23
  lastYearFields?: string[];
24
24
  }
25
25
  export interface ReportConfig<TField extends string = string> {
26
- fields: Record<TField, ColumnPresentationConfig>;
26
+ fields: Record<TField, ColumnPresentationConfig<TField>>;
27
27
  availableColumns: TField[];
28
28
  defaultVisibleColumns: TField[];
29
29
  columnGroups?: ColumnGroupConfig[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harbortouch/skytab-analytics-report-utils",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "Centralized report column presentation configuration for SkyTab Analytics",
5
5
  "engines": {
6
6
  "node": ">=22.6.0",