@cranberry-money/shared-utils 8.2.0 → 8.4.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.
@@ -0,0 +1,72 @@
1
+ import type { AssetAllocation, AssetHolding } from '@cranberry-money/shared-types';
2
+ /**
3
+ * Display item interface for allocation data
4
+ */
5
+ export interface AllocationDisplayItem {
6
+ readonly instrumentUuid: string;
7
+ readonly symbol: string;
8
+ readonly name: string;
9
+ readonly targetPercentage?: number;
10
+ readonly actualPercentage?: number;
11
+ readonly quantity?: number;
12
+ readonly value?: number;
13
+ readonly currentPrice?: number;
14
+ readonly color: string;
15
+ readonly hasTarget: boolean;
16
+ readonly hasActual: boolean;
17
+ }
18
+ /**
19
+ * Processes allocation and holding data for dashboard display
20
+ * Merges target allocations with actual holdings data
21
+ *
22
+ * @param allocations - Target asset allocations
23
+ * @param holdings - Actual asset holdings
24
+ * @returns Array of display items sorted by target/actual percentage
25
+ *
26
+ * @example
27
+ * const allocations = [{ instrument: '123', percentage: '50.00', ... }];
28
+ * const holdings = [{ instrument: { uuid: '123' }, quantity: 100, ... }];
29
+ * processAllocationData(allocations, holdings);
30
+ */
31
+ export declare const processAllocationData: (allocations: readonly AssetAllocation[], holdings: readonly AssetHolding[]) => AllocationDisplayItem[];
32
+ /**
33
+ * Calculates totals from allocation display items
34
+ *
35
+ * @param items - Array of allocation display items
36
+ * @returns Object with total calculations
37
+ *
38
+ * @example
39
+ * const items = [{ targetPercentage: 50, actualPercentage: 45, value: 1000, quantity: 10 }];
40
+ * calculateTotals(items);
41
+ * // returns { totalTarget: 50, totalActual: 45, totalValue: 1000, totalQuantity: 10 }
42
+ */
43
+ export declare const calculateTotals: (items: readonly AllocationDisplayItem[]) => {
44
+ totalTarget: number;
45
+ totalActual: number;
46
+ totalValue: number;
47
+ totalQuantity: number;
48
+ };
49
+ /**
50
+ * Formats a percentage value for display
51
+ *
52
+ * @param value - The percentage value to format
53
+ * @returns Formatted percentage string
54
+ *
55
+ * @example
56
+ * formatPercentage(45.678); // returns "45.7%"
57
+ * formatPercentage(undefined); // returns "0.0%"
58
+ */
59
+ export declare const formatPercentage: (value?: number) => string;
60
+ /**
61
+ * Formats currency value for dashboard display
62
+ *
63
+ * @param value - The numeric value to format
64
+ * @param currency - Currency code (defaults to DEFAULT_CURRENCY)
65
+ * @returns Formatted currency string or "—" for undefined values
66
+ *
67
+ * @example
68
+ * formatDashboardCurrency(1234.56); // returns "$1,234.56"
69
+ * formatDashboardCurrency(undefined); // returns "—"
70
+ */
71
+ export declare const formatDashboardCurrency: (value?: number, currency?: string) => string;
72
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAMnF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,GAChC,aAAa,SAAS,eAAe,EAAE,EACvC,UAAU,SAAS,YAAY,EAAE,KAChC,qBAAqB,EAwEvB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,SAAS,qBAAqB,EAAE;;;;;CAOtE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,MAGjD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,EAAE,WAAU,MAAyB,KAAG,MAG7F,CAAC"}
@@ -0,0 +1,121 @@
1
+ import { DEFAULT_CURRENCY } from '@cranberry-money/shared-constants';
2
+ import { getChartColor } from '@cranberry-money/shared-constants';
3
+ import { formatCurrencyWithCode } from './currency';
4
+ import { calculateHoldingAllocations } from './holdings';
5
+ /**
6
+ * Processes allocation and holding data for dashboard display
7
+ * Merges target allocations with actual holdings data
8
+ *
9
+ * @param allocations - Target asset allocations
10
+ * @param holdings - Actual asset holdings
11
+ * @returns Array of display items sorted by target/actual percentage
12
+ *
13
+ * @example
14
+ * const allocations = [{ instrument: '123', percentage: '50.00', ... }];
15
+ * const holdings = [{ instrument: { uuid: '123' }, quantity: 100, ... }];
16
+ * processAllocationData(allocations, holdings);
17
+ */
18
+ export const processAllocationData = (allocations, holdings) => {
19
+ const actualAllocations = calculateHoldingAllocations(holdings);
20
+ const instrumentMap = new Map();
21
+ // Process target allocations
22
+ allocations.forEach((allocation) => {
23
+ instrumentMap.set(allocation.instrument, {
24
+ symbol: allocation.instrumentSymbol,
25
+ name: allocation.instrumentName,
26
+ targetPercentage: parseFloat(allocation.percentage),
27
+ });
28
+ });
29
+ // Process actual holdings
30
+ holdings.forEach((holding) => {
31
+ const existing = instrumentMap.get(holding.instrument.uuid);
32
+ const currentPrice = parseFloat(holding.instrument.currentPrice || '0');
33
+ const value = holding.quantity * currentPrice;
34
+ instrumentMap.set(holding.instrument.uuid, {
35
+ symbol: holding.instrumentSymbol,
36
+ name: holding.instrumentName,
37
+ targetPercentage: existing?.targetPercentage,
38
+ actualPercentage: actualAllocations[holding.instrument.uuid] || 0,
39
+ quantity: holding.quantity,
40
+ currentPrice,
41
+ value,
42
+ });
43
+ });
44
+ // Convert to display items
45
+ const items = [];
46
+ let colorIndex = 0;
47
+ instrumentMap.forEach((data, instrumentUuid) => {
48
+ items.push({
49
+ instrumentUuid,
50
+ symbol: data.symbol,
51
+ name: data.name,
52
+ targetPercentage: data.targetPercentage,
53
+ actualPercentage: data.actualPercentage,
54
+ quantity: data.quantity,
55
+ currentPrice: data.currentPrice,
56
+ value: data.value,
57
+ color: getChartColor(colorIndex++),
58
+ hasTarget: data.targetPercentage !== undefined,
59
+ hasActual: data.actualPercentage !== undefined && data.actualPercentage > 0,
60
+ });
61
+ });
62
+ // Sort by target percentage (highest first), then by actual percentage
63
+ return items.sort((a, b) => {
64
+ const aTarget = a.targetPercentage || 0;
65
+ const bTarget = b.targetPercentage || 0;
66
+ if (aTarget !== bTarget)
67
+ return bTarget - aTarget;
68
+ const aActual = a.actualPercentage || 0;
69
+ const bActual = b.actualPercentage || 0;
70
+ return bActual - aActual;
71
+ });
72
+ };
73
+ /**
74
+ * Calculates totals from allocation display items
75
+ *
76
+ * @param items - Array of allocation display items
77
+ * @returns Object with total calculations
78
+ *
79
+ * @example
80
+ * const items = [{ targetPercentage: 50, actualPercentage: 45, value: 1000, quantity: 10 }];
81
+ * calculateTotals(items);
82
+ * // returns { totalTarget: 50, totalActual: 45, totalValue: 1000, totalQuantity: 10 }
83
+ */
84
+ export const calculateTotals = (items) => {
85
+ const totalTarget = items.reduce((sum, item) => sum + (item.targetPercentage || 0), 0);
86
+ const totalActual = items.reduce((sum, item) => sum + (item.actualPercentage || 0), 0);
87
+ const totalValue = items.reduce((sum, item) => sum + (item.value || 0), 0);
88
+ const totalQuantity = items.reduce((sum, item) => sum + (item.quantity || 0), 0);
89
+ return { totalTarget, totalActual, totalValue, totalQuantity };
90
+ };
91
+ /**
92
+ * Formats a percentage value for display
93
+ *
94
+ * @param value - The percentage value to format
95
+ * @returns Formatted percentage string
96
+ *
97
+ * @example
98
+ * formatPercentage(45.678); // returns "45.7%"
99
+ * formatPercentage(undefined); // returns "0.0%"
100
+ */
101
+ export const formatPercentage = (value) => {
102
+ if (value === undefined)
103
+ return '0.0%';
104
+ return `${value.toFixed(1)}%`;
105
+ };
106
+ /**
107
+ * Formats currency value for dashboard display
108
+ *
109
+ * @param value - The numeric value to format
110
+ * @param currency - Currency code (defaults to DEFAULT_CURRENCY)
111
+ * @returns Formatted currency string or "—" for undefined values
112
+ *
113
+ * @example
114
+ * formatDashboardCurrency(1234.56); // returns "$1,234.56"
115
+ * formatDashboardCurrency(undefined); // returns "—"
116
+ */
117
+ export const formatDashboardCurrency = (value, currency = DEFAULT_CURRENCY) => {
118
+ if (value === undefined || value === null)
119
+ return '—';
120
+ return formatCurrencyWithCode(value, currency, 'en-AU', 2, 2);
121
+ };
package/dist/index.d.ts CHANGED
@@ -21,4 +21,6 @@ export { capitalizeFirstLetter, formatStatus, formatRiskLevel, capitalizeFirst,
21
21
  export { formatQuantityWithSuffix, formatLargeNumber, formatAsPercentage, formatWithSeparators, roundToDecimals, clampNumber, } from './numbers';
22
22
  export { validateAllocations } from './allocations';
23
23
  export { calculatePortfolioValue, calculateHoldingAllocations, groupHoldingsByInstrument, filterHoldingsByMinQuantity, sortHoldings, } from './holdings';
24
+ export { processAllocationData, calculateTotals, formatPercentage, formatDashboardCurrency, type AllocationDisplayItem, } from './dashboard';
25
+ export { isValidTemplateSelection, validatePortfolioSelection, type PortfolioSelectionValidation, type PortfolioSelectionState, } from './portfolio-validation';
24
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -42,3 +42,7 @@ export { formatQuantityWithSuffix, formatLargeNumber, formatAsPercentage, format
42
42
  export { validateAllocations } from './allocations';
43
43
  // Holdings utilities
44
44
  export { calculatePortfolioValue, calculateHoldingAllocations, groupHoldingsByInstrument, filterHoldingsByMinQuantity, sortHoldings, } from './holdings';
45
+ // Dashboard utilities
46
+ export { processAllocationData, calculateTotals, formatPercentage, formatDashboardCurrency, } from './dashboard';
47
+ // Portfolio validation utilities
48
+ export { isValidTemplateSelection, validatePortfolioSelection, } from './portfolio-validation';
@@ -0,0 +1,42 @@
1
+ import type { MessageFieldValidation, BaseFormValidation } from '@cranberry-money/shared-types';
2
+ /**
3
+ * Portfolio selection form validation interface
4
+ */
5
+ export interface PortfolioSelectionValidation extends BaseFormValidation {
6
+ readonly selectedTemplate: MessageFieldValidation;
7
+ }
8
+ /**
9
+ * Portfolio selection state interface
10
+ */
11
+ export interface PortfolioSelectionState {
12
+ readonly selectedTemplateUuid: string | null;
13
+ readonly viewingDetailsForUuid?: string | null;
14
+ }
15
+ /**
16
+ * Validates if a portfolio template is selected
17
+ *
18
+ * @param selectedTemplateUuid - The UUID of the selected template
19
+ * @returns true if a template is selected, false otherwise
20
+ *
21
+ * @example
22
+ * isValidTemplateSelection('123-456'); // returns true
23
+ * isValidTemplateSelection(null); // returns false
24
+ * isValidTemplateSelection(''); // returns false
25
+ */
26
+ export declare const isValidTemplateSelection: (selectedTemplateUuid: string | null) => boolean;
27
+ /**
28
+ * Comprehensive validation for portfolio selection form
29
+ *
30
+ * @param state - The portfolio selection state
31
+ * @returns Validation object with field-level and form-level validity
32
+ *
33
+ * @example
34
+ * const state = { selectedTemplateUuid: '123-456' };
35
+ * validatePortfolioSelection(state);
36
+ * // returns {
37
+ * // selectedTemplate: { isValid: true, message: '' },
38
+ * // isFormValid: true
39
+ * // }
40
+ */
41
+ export declare const validatePortfolioSelection: (state: PortfolioSelectionState) => PortfolioSelectionValidation;
42
+ //# sourceMappingURL=portfolio-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portfolio-validation.d.ts","sourceRoot":"","sources":["../src/portfolio-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEhG;;GAEG;AACH,MAAM,WAAW,4BAA6B,SAAQ,kBAAkB;IACtE,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,sBAAsB,MAAM,GAAG,IAAI,KAAG,OAE9E,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,0BAA0B,GAAI,OAAO,uBAAuB,KAAG,4BAa3E,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Validates if a portfolio template is selected
3
+ *
4
+ * @param selectedTemplateUuid - The UUID of the selected template
5
+ * @returns true if a template is selected, false otherwise
6
+ *
7
+ * @example
8
+ * isValidTemplateSelection('123-456'); // returns true
9
+ * isValidTemplateSelection(null); // returns false
10
+ * isValidTemplateSelection(''); // returns false
11
+ */
12
+ export const isValidTemplateSelection = (selectedTemplateUuid) => {
13
+ return Boolean(selectedTemplateUuid);
14
+ };
15
+ /**
16
+ * Comprehensive validation for portfolio selection form
17
+ *
18
+ * @param state - The portfolio selection state
19
+ * @returns Validation object with field-level and form-level validity
20
+ *
21
+ * @example
22
+ * const state = { selectedTemplateUuid: '123-456' };
23
+ * validatePortfolioSelection(state);
24
+ * // returns {
25
+ * // selectedTemplate: { isValid: true, message: '' },
26
+ * // isFormValid: true
27
+ * // }
28
+ */
29
+ export const validatePortfolioSelection = (state) => {
30
+ const validation = {
31
+ selectedTemplate: {
32
+ isValid: isValidTemplateSelection(state.selectedTemplateUuid),
33
+ message: isValidTemplateSelection(state.selectedTemplateUuid) ? '' : 'Please select a portfolio template',
34
+ },
35
+ isFormValid: false,
36
+ };
37
+ // Overall form validity
38
+ validation.isFormValid = validation.selectedTemplate.isValid;
39
+ return validation;
40
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cranberry-money/shared-utils",
3
- "version": "8.2.0",
3
+ "version": "8.4.0",
4
4
  "description": "Shared utility functions for MyPortfolio platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",