| 6 | 6 | } |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | // Constants for formatting |
| 10 | const DATE_PADDING = 10; |
| 11 | const DESCRIPTION_PADDING = 25; |
| 12 | const CHANGE_PADDING = 13; |
| 13 | const DESCRIPTION_MAX_LENGTH = 22; |
| 14 | const CENTS_PER_DOLLAR = 100; |
| 15 | |
| 16 | // Date formatting functions |
| 17 | function formatDateUS(date) { |
| 18 | const month = (date.getMonth() + 1).toString().padStart(2, "0"); |
| 19 | const day = date.getDate().toString().padStart(2, "0"); |
| 20 | const year = date.getFullYear(); |
| 21 | return `${month}/${day}/${year}`; |
| 22 | } |
| 23 | |
| 24 | function formatDateDutch(date) { |
| 25 | const day = date.getDate().toString().padStart(2, "0"); |
| 26 | const month = (date.getMonth() + 1).toString().padStart(2, "0"); |
| 27 | const year = date.getFullYear(); |
| 28 | return `${day}-${month}-${year}`; |
| 29 | } |
| 30 | |
| 31 | // Description formatting function |
| 32 | function formatDescription(description) { |
| 33 | return description.length > DESCRIPTION_PADDING |
| 34 | ? `${description.substring(0, DESCRIPTION_MAX_LENGTH)}...` |
| 35 | : description.padEnd(DESCRIPTION_PADDING, " "); |
| 36 | } |
| 37 | |
| 38 | // Currency formatting functions |
| 39 | function formatCurrencyUS(change, currency) { |
| 40 | const formattingOptions = { |
| 41 | style: "currency", |
| 42 | currency: currency, |
| 43 | minimumFractionDigits: 2, |
| 44 | maximumFractionDigits: 2, |
| 45 | }; |
| 46 | |
| 47 | if (change < 0) { |
| 48 | return `(${Math.abs(change / CENTS_PER_DOLLAR).toLocaleString("en-US", formattingOptions)})`; |
| 49 | } else { |
| 50 | return `${(change / CENTS_PER_DOLLAR).toLocaleString("en-US", formattingOptions)} `; |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | function formatCurrencyDutch(change, currency) { |
| 55 | const formattingOptions = { |
| 56 | style: "currency", |
| 57 | currency: currency, |
| 58 | currencyDisplay: "narrowSymbol", |
| 59 | minimumFractionDigits: 2, |
| 60 | maximumFractionDigits: 2, |
| 61 | }; |
| 62 | |
| 63 | return `${(change / CENTS_PER_DOLLAR).toLocaleString("nl-NL", formattingOptions)} `; |
| 64 | } |
| 65 | |
| 66 | // Header generation functions |
| 67 | function generateHeaderUS() { |
| 68 | return ( |
| 69 | "Date".padEnd(DATE_PADDING, " ") + |
| 70 | " | " + |
| 71 | "Description".padEnd(DESCRIPTION_PADDING, " ") + |
| 72 | " | " + |
| 73 | "Change".padEnd(CHANGE_PADDING, " ") + |
| 74 | "\n" |
| 75 | ); |
| 76 | } |
| 77 | |
| 78 | function generateHeaderDutch() { |
| 79 | return ( |
| 80 | "Datum".padEnd(DATE_PADDING, " ") + |
| 81 | " | " + |
| 82 | "Omschrijving".padEnd(DESCRIPTION_PADDING, " ") + |
| 83 | " | " + |
| 84 | "Verandering".padEnd(CHANGE_PADDING, " ") + |
| 85 | "\n" |
| 86 | ); |
| 87 | } |
| 88 | |
| 89 | // Sorting function |
| 90 | function sortEntries(entries) { |
| 91 | entries.sort( |
| 92 | (a, b) => |
| 93 | a.date - b.date || |
| 94 | a.change - b.change || |
| 95 | a.description.localeCompare(b.description), |
| 96 | ); |
| 97 | } |
| 98 | |
| 9 | 99 | /** |
| 10 | 100 | * @param {string} date |
| 11 | 101 | * @param {string} description |
| 28 | 118 | */ |
| 29 | 119 | export function formatEntries(currency, locale, entries) { |
| 30 | 120 | let table = ''; |
| 121 | |
| 122 | // Sort entries |
| 123 | entries.sort( |
| 124 | (a, b) => |
| 125 | a.date - b.date || |
| 126 | a.change - b.change || |
| 127 | a.description.localeCompare(b.description), |
| 128 | ); |
| 129 | |
| 31 | 130 | if (locale === 'en-US') { |
| 32 | | // Generate Header Row |
| 33 | | table += |
| 34 | | 'Date'.padEnd(10, ' ') + |
| 35 | | ' | ' + |
| 36 | | 'Description'.padEnd(25, ' ') + |
| 37 | | ' | ' + |
| 38 | | 'Change'.padEnd(13, ' ') + |
| 39 | | '\n'; |
| 40 | | |
| 41 | | // Sort entries |
| 42 | | entries.sort( |
| 43 | | (a, b) => |
| 44 | | a.date - b.date || |
| 45 | | a.change - b.change || |
| 46 | | a.description.localeCompare(b.description), |
| 47 | | ); |
| 48 | | |
| 49 | | entries.forEach((entry) => { |
| 50 | | // Write entry date to table |
| 51 | | const dateStr = `${(entry.date.getMonth() + 1) |
| 52 | | .toString() |
| 53 | | .padStart(2, '0')}/${entry.date |
| 54 | | .getDate() |
| 55 | | .toString() |
| 56 | | .padStart(2, '0')}/${entry.date.getFullYear()}`; |
| 57 | | table += `${dateStr} | `; |
| 58 | | |
| 59 | | // Write entry description to table |
| 60 | | const truncatedDescription = |
| 61 | | entry.description.length > 25 |
| 62 | | ? `${entry.description.substring(0, 22)}...` |
| 63 | | : entry.description.padEnd(25, ' '); |
| 64 | | table += `${truncatedDescription} | `; |
| 65 | | |
| 66 | | // Write entry change to table |
| 67 | | let changeStr = ''; |
| 68 | | if (currency === 'USD') { |
| 69 | | let formatingOptions = { |
| 70 | | style: 'currency', |
| 71 | | currency: 'USD', |
| 72 | | //currencySign: 'accounting', |
| 73 | | minimumFractionDigits: 2, |
| 74 | | maximumFractionDigits: 2, |
| 75 | | }; |
| 76 | | if (entry.change < 0) { |
| 77 | | changeStr = `(${Math.abs(entry.change / 100).toLocaleString( |
| 78 | | 'en-US', |
| 79 | | formatingOptions, |
| 80 | | )})`; |
| 81 | | } else { |
| 82 | | changeStr = `${(entry.change / 100).toLocaleString( |
| 83 | | 'en-US', |
| 84 | | formatingOptions, |
| 85 | | )} `; |
| 86 | | } |
| 87 | | } else if (currency === 'EUR') { |
| 88 | | let formatingOptions = { |
| 89 | | style: 'currency', |
| 90 | | currency: 'EUR', |
| 91 | | minimumFractionDigits: 2, |
| 92 | | maximumFractionDigits: 2, |
| 93 | | }; |
| 94 | | if (entry.change < 0) { |
| 95 | | changeStr = `(${Math.abs(entry.change / 100).toLocaleString( |
| 96 | | 'en-US', |
| 97 | | formatingOptions, |
| 98 | | )})`; |
| 99 | | } else { |
| 100 | | changeStr = `${(entry.change / 100).toLocaleString( |
| 101 | | 'en-US', |
| 102 | | formatingOptions, |
| 103 | | )} `; |
| 104 | | } |
| 105 | | } |
| 106 | | table += changeStr.padStart(13, ' '); |
| 107 | | table += '\n'; |
| 108 | | }); |
| 131 | table = buildTableUS(entries, currency); |
| 109 | 132 | } else if (locale === 'nl-NL') { |
| 110 | | // Generate Header Row |
| 111 | | table += |
| 112 | | 'Datum'.padEnd(10, ' ') + |
| 113 | | ' | ' + |
| 114 | | 'Omschrijving'.padEnd(25, ' ') + |
| 115 | | ' | ' + |
| 116 | | 'Verandering'.padEnd(13, ' ') + |
| 117 | | '\n'; |
| 118 | | |
| 119 | | // Sort entries |
| 120 | | entries.sort( |
| 121 | | (a, b) => |
| 122 | | a.date - b.date || |
| 123 | | a.change - b.change || |
| 124 | | a.description.localeCompare(b.description), |
| 125 | | ); |
| 126 | | |
| 127 | | entries.forEach((entry) => { |
| 128 | | // Write entry date to table |
| 129 | | const dateStr = `${entry.date.getDate().toString().padStart(2, '0')}-${( |
| 130 | | entry.date.getMonth() + 1 |
| 131 | | ) |
| 132 | | .toString() |
| 133 | | .padStart(2, '0')}-${entry.date.getFullYear()}`; |
| 134 | | table += `${dateStr} | `; |
| 135 | | |
| 136 | | // Write entry description to table |
| 137 | | const truncatedDescription = |
| 138 | | entry.description.length > 25 |
| 139 | | ? `${entry.description.substring(0, 22)}...` |
| 140 | | : entry.description.padEnd(25, ' '); |
| 141 | | table += `${truncatedDescription} | `; |
| 142 | | |
| 143 | | // Write entry change to table |
| 144 | | let changeStr = ''; |
| 145 | | if (currency === 'USD') { |
| 146 | | let formatingOptions = { |
| 147 | | style: 'currency', |
| 148 | | currency: 'USD', |
| 149 | | currencyDisplay: 'narrowSymbol', |
| 150 | | minimumFractionDigits: 2, |
| 151 | | maximumFractionDigits: 2, |
| 152 | | }; |
| 153 | | changeStr = `${(entry.change / 100).toLocaleString( |
| 154 | | 'nl-NL', |
| 155 | | formatingOptions, |
| 156 | | )} `; |
| 157 | | } else if (currency === 'EUR') { |
| 158 | | let formatingOptions = { |
| 159 | | style: 'currency', |
| 160 | | currency: 'EUR', |
| 161 | | currencyDisplay: 'narrowSymbol', |
| 162 | | minimumFractionDigits: 2, |
| 163 | | maximumFractionDigits: 2, |
| 164 | | }; |
| 165 | | changeStr = `${(entry.change / 100).toLocaleString( |
| 166 | | 'nl-NL', |
| 167 | | formatingOptions, |
| 168 | | )} `; |
| 169 | | } |
| 170 | | table += changeStr.padStart(13, ' '); |
| 171 | | table += '\n'; |
| 172 | | }); |
| 133 | table = buildTableDutch(entries, currency); |
| 173 | 134 | } |
| 135 | |
| 174 | 136 | return table.replace(/\n$/, ''); |
| 175 | 137 | } |
| 138 | |
| 139 | function buildTableUS(entries, currency) { |
| 140 | let table = generateHeaderUS(); |
| 141 | |
| 142 | entries.forEach((entry) => { |
| 143 | // Write entry date to table |
| 144 | const dateStr = formatDateUS(entry.date); |
| 145 | table += `${dateStr} | `; |
| 146 | |
| 147 | // Write entry description to table |
| 148 | const truncatedDescription = formatDescription(entry.description); |
| 149 | table += `${truncatedDescription} | `; |
| 150 | |
| 151 | // Write entry change to table |
| 152 | const changeStr = formatCurrencyUS(entry.change, currency); |
| 153 | table += changeStr.padStart(CHANGE_PADDING, " "); |
| 154 | table += "\n"; |
| 155 | }); |
| 156 | |
| 157 | return table; |
| 158 | } |
| 159 | |
| 160 | function buildTableDutch(entries, currency) { |
| 161 | let table = generateHeaderDutch(); |
| 162 | |
| 163 | entries.forEach((entry) => { |
| 164 | // Write entry date to table |
| 165 | const dateStr = formatDateDutch(entry.date); |
| 166 | table += `${dateStr} | `; |
| 167 | |
| 168 | // Write entry description to table |
| 169 | const truncatedDescription = formatDescription(entry.description); |
| 170 | table += `${truncatedDescription} | `; |
| 171 | |
| 172 | // Write entry change to table |
| 173 | const changeStr = formatCurrencyDutch(entry.change, currency); |
| 174 | table += changeStr.padStart(CHANGE_PADDING, " "); |
| 175 | table += "\n"; |
| 176 | }); |
| 177 | |
| 178 | return table; |
| 179 | } |