@jjlmoya/utils-finance 1.43.0 → 1.45.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.
Files changed (35) hide show
  1. package/package.json +2 -2
  2. package/scripts/validate-icons.mjs +57 -0
  3. package/src/category/index.ts +2 -1
  4. package/src/entries.ts +4 -1
  5. package/src/tests/locale_completeness.test.ts +2 -2
  6. package/src/tests/tool_validation.test.ts +2 -2
  7. package/src/tool/insuranceDeductibleBreakEvenCalculator/bibliography.astro +10 -0
  8. package/src/tool/insuranceDeductibleBreakEvenCalculator/bibliography.ts +6 -0
  9. package/src/tool/insuranceDeductibleBreakEvenCalculator/component.astro +172 -0
  10. package/src/tool/insuranceDeductibleBreakEvenCalculator/currency.test.ts +13 -0
  11. package/src/tool/insuranceDeductibleBreakEvenCalculator/currency.ts +26 -0
  12. package/src/tool/insuranceDeductibleBreakEvenCalculator/entry.ts +28 -0
  13. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/content-factory.ts +147 -0
  14. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/de.ts +2 -0
  15. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/en.ts +100 -0
  16. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/es.ts +2 -0
  17. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/fr.ts +2 -0
  18. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/id.ts +2 -0
  19. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/it.ts +2 -0
  20. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/ja.ts +2 -0
  21. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/ko.ts +2 -0
  22. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/nl.ts +2 -0
  23. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/pl.ts +2 -0
  24. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/pt.ts +2 -0
  25. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/ru.ts +2 -0
  26. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/sv.ts +2 -0
  27. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/tr.ts +2 -0
  28. package/src/tool/insuranceDeductibleBreakEvenCalculator/i18n/zh.ts +2 -0
  29. package/src/tool/insuranceDeductibleBreakEvenCalculator/index.ts +11 -0
  30. package/src/tool/insuranceDeductibleBreakEvenCalculator/insurance-deductible-break-even-calculator.css +424 -0
  31. package/src/tool/insuranceDeductibleBreakEvenCalculator/logic.test.ts +40 -0
  32. package/src/tool/insuranceDeductibleBreakEvenCalculator/logic.ts +72 -0
  33. package/src/tool/insuranceDeductibleBreakEvenCalculator/seo.astro +11 -0
  34. package/src/tool/insuranceDeductibleBreakEvenCalculator/ui.ts +33 -0
  35. package/src/tools.ts +2 -1
@@ -0,0 +1,424 @@
1
+ :root {
2
+ --idb-ink: #25251f;
3
+ --idb-muted: #716c60;
4
+ --idb-paper: #fbf8ef;
5
+ --idb-surface: #f0eadb;
6
+ --idb-edge: #d6c9aa;
7
+ --idb-claim: #36747b;
8
+ --idb-claim-soft: #d6e8e4;
9
+ --idb-pay: #b5533b;
10
+ --idb-pay-soft: #efd8c8;
11
+ --idb-gold: #bf8a37;
12
+ --idb-on-accent: #fffaf1;
13
+ --idb-shadow: #51463122;
14
+ }
15
+
16
+ :global(.theme-dark) {
17
+ --idb-ink: #f3eee3;
18
+ --idb-muted: #bbb3a4;
19
+ --idb-paper: #24251f;
20
+ --idb-surface: #2d3028;
21
+ --idb-edge: #565446;
22
+ --idb-claim: #84c3c3;
23
+ --idb-claim-soft: #294b4b;
24
+ --idb-pay: #df8663;
25
+ --idb-pay-soft: #5b352b;
26
+ --idb-gold: #e1b45d;
27
+ --idb-on-accent: #281d18;
28
+ --idb-shadow: #0006;
29
+ }
30
+
31
+ .idb-tool {
32
+ background: var(--idb-paper);
33
+ border: 1px solid var(--idb-edge);
34
+ border-radius: 1.35rem;
35
+ box-shadow: 0 1rem 2.5rem var(--idb-shadow);
36
+ color: var(--idb-ink);
37
+ margin: 0 auto;
38
+ max-width: 74rem;
39
+ overflow: hidden;
40
+ width: min(100%, calc(100vw - 2rem));
41
+ }
42
+
43
+ .idb-card {
44
+ display: grid;
45
+ gap: 1.35rem;
46
+ padding: 1.35rem;
47
+ }
48
+
49
+ .idb-glance {
50
+ align-items: stretch;
51
+ background: var(--idb-surface);
52
+ border: 1px solid var(--idb-edge);
53
+ border-radius: 1rem;
54
+ display: grid;
55
+ gap: 1px;
56
+ grid-template-columns: repeat(2, 1fr);
57
+ overflow: hidden;
58
+ }
59
+
60
+ .idb-glance > div {
61
+ display: grid;
62
+ gap: 0.35rem;
63
+ padding: 1rem;
64
+ }
65
+
66
+ .idb-glance > div + div {
67
+ border-left: 1px solid var(--idb-edge);
68
+ }
69
+
70
+ .idb-glance span,
71
+ .idb-result-grid span,
72
+ .idb-visual-heading,
73
+ .idb-help,
74
+ .idb-method,
75
+ .idb-privacy,
76
+ .idb-result-note {
77
+ color: var(--idb-muted);
78
+ font-size: 0.78rem;
79
+ line-height: 1.45;
80
+ }
81
+
82
+ .idb-glance strong {
83
+ font-size: clamp(1.15rem, 2.4vw, 1.65rem);
84
+ line-height: 1.1;
85
+ }
86
+
87
+ .idb-inputs {
88
+ display: grid;
89
+ gap: 1rem;
90
+ grid-template-columns: repeat(2, minmax(0, 1fr));
91
+ }
92
+
93
+ .idb-field {
94
+ display: grid;
95
+ gap: 0.38rem;
96
+ }
97
+
98
+ .idb-field label,
99
+ .idb-label {
100
+ font-size: 0.82rem;
101
+ font-weight: 800;
102
+ }
103
+
104
+ .idb-input-wrap {
105
+ align-items: center;
106
+ background: var(--idb-paper);
107
+ border: 1px solid var(--idb-edge);
108
+ border-radius: 0.65rem;
109
+ display: flex;
110
+ min-height: 2.8rem;
111
+ overflow: hidden;
112
+ }
113
+
114
+ .idb-input-wrap input {
115
+ background: transparent;
116
+ border: 0;
117
+ box-sizing: border-box;
118
+ color: var(--idb-ink);
119
+ font: inherit;
120
+ min-width: 0;
121
+ outline: 0;
122
+ padding: 0.62rem 0.7rem;
123
+ width: 100%;
124
+ }
125
+
126
+ .idb-input-wrap span {
127
+ color: var(--idb-muted);
128
+ font-size: 0.85rem;
129
+ padding: 0 0.7rem;
130
+ }
131
+
132
+ .idb-field > small:not(.idb-help) {
133
+ color: var(--idb-pay);
134
+ font-size: 0.74rem;
135
+ }
136
+
137
+ .idb-field > small[hidden] {
138
+ display: none;
139
+ }
140
+
141
+ .idb-input-wrap:focus-within,
142
+ .idb-currency:focus-visible,
143
+ .idb-button:focus-visible,
144
+ .idb-method summary:focus-visible {
145
+ outline: 3px solid var(--idb-gold);
146
+ outline-offset: 2px;
147
+ }
148
+
149
+ .idb-currency-field,
150
+ .idb-currency-select {
151
+ position: relative;
152
+ }
153
+
154
+ .idb-currency-trigger {
155
+ align-items: center;
156
+ background: var(--idb-paper);
157
+ border: 1px solid var(--idb-edge);
158
+ border-radius: 0.65rem;
159
+ color: var(--idb-ink);
160
+ cursor: pointer;
161
+ display: flex;
162
+ font: inherit;
163
+ justify-content: space-between;
164
+ min-height: 2.8rem;
165
+ padding: 0.62rem 0.7rem;
166
+ text-align: left;
167
+ width: 100%;
168
+ }
169
+
170
+ .idb-currency-trigger-main {
171
+ align-items: center;
172
+ display: flex;
173
+ gap: 0.55rem;
174
+ }
175
+
176
+ .idb-currency-trigger-main strong {
177
+ font-size: 1.1rem;
178
+ line-height: 1;
179
+ }
180
+
181
+ .idb-currency-arrow {
182
+ border-bottom: 2px solid var(--idb-claim);
183
+ border-right: 2px solid var(--idb-claim);
184
+ height: 0.45rem;
185
+ transform: rotate(45deg) translateY(-0.15rem);
186
+ transition: transform 160ms ease;
187
+ width: 0.45rem;
188
+ }
189
+
190
+ .idb-currency-trigger[aria-expanded="true"] .idb-currency-arrow {
191
+ transform: rotate(225deg) translateY(-0.05rem);
192
+ }
193
+
194
+ .idb-currency-menu {
195
+ background: var(--idb-paper);
196
+ border: 1px solid var(--idb-edge);
197
+ border-radius: 0.75rem;
198
+ box-shadow: 0 1rem 2rem var(--idb-shadow);
199
+ display: grid;
200
+ gap: 0.35rem;
201
+ grid-template-columns: repeat(5, minmax(0, 1fr));
202
+ left: 0;
203
+ padding: 0.5rem;
204
+ position: absolute;
205
+ right: 0;
206
+ top: calc(100% + 0.4rem);
207
+ z-index: 20;
208
+ }
209
+
210
+ .idb-currency-menu[hidden] {
211
+ display: none;
212
+ }
213
+
214
+ .idb-currency-option {
215
+ align-items: center;
216
+ background: transparent;
217
+ border: 1px solid transparent;
218
+ border-radius: 0.55rem;
219
+ color: var(--idb-ink);
220
+ cursor: pointer;
221
+ display: flex;
222
+ font: inherit;
223
+ gap: 0.35rem;
224
+ justify-content: center;
225
+ min-width: 0;
226
+ padding: 0.55rem 0.3rem;
227
+ }
228
+
229
+ .idb-currency-option span {
230
+ color: var(--idb-muted);
231
+ font-size: 0.7rem;
232
+ font-weight: 800;
233
+ }
234
+
235
+ .idb-currency-option[aria-selected="true"],
236
+ .idb-currency-option:hover {
237
+ background: var(--idb-claim-soft);
238
+ border-color: var(--idb-claim);
239
+ color: var(--idb-claim);
240
+ }
241
+
242
+ .idb-help {
243
+ margin: 0;
244
+ }
245
+
246
+ .idb-actions {
247
+ align-items: center;
248
+ display: flex;
249
+ flex-wrap: wrap;
250
+ gap: 0.7rem;
251
+ }
252
+
253
+ .idb-button {
254
+ border: 1px solid var(--idb-claim);
255
+ border-radius: 99rem;
256
+ cursor: pointer;
257
+ font: inherit;
258
+ font-weight: 800;
259
+ min-height: 2.75rem;
260
+ padding: 0.55rem 1rem;
261
+ }
262
+
263
+ .idb-button-primary {
264
+ background: var(--idb-claim);
265
+ color: var(--idb-on-accent);
266
+ }
267
+
268
+ .idb-button-secondary {
269
+ background: transparent;
270
+ color: var(--idb-claim);
271
+ }
272
+
273
+ .idb-actions [role="status"] {
274
+ color: var(--idb-muted);
275
+ font-size: 0.78rem;
276
+ }
277
+
278
+ .idb-output {
279
+ border-top: 1px solid var(--idb-edge);
280
+ display: grid;
281
+ gap: 1rem;
282
+ padding-top: 1.35rem;
283
+ }
284
+
285
+ .idb-visual {
286
+ background: var(--idb-surface);
287
+ border: 1px solid var(--idb-edge);
288
+ border-radius: 1rem;
289
+ display: grid;
290
+ gap: 0.8rem;
291
+ padding: 1rem;
292
+ }
293
+
294
+ .idb-visual-heading {
295
+ display: flex;
296
+ font-weight: 800;
297
+ justify-content: space-between;
298
+ }
299
+
300
+ .idb-bars {
301
+ align-items: end;
302
+ display: grid;
303
+ gap: 0.75rem;
304
+ grid-template-columns: 1fr auto 1fr;
305
+ }
306
+
307
+ .idb-bar-side {
308
+ display: grid;
309
+ gap: 0.4rem;
310
+ }
311
+
312
+ .idb-bar-side:first-child {
313
+ text-align: left;
314
+ }
315
+
316
+ .idb-bar-side:last-child {
317
+ text-align: right;
318
+ }
319
+
320
+ .idb-bar-track {
321
+ background: var(--idb-paper);
322
+ border: 1px solid var(--idb-edge);
323
+ border-radius: 99rem;
324
+ height: 1rem;
325
+ overflow: hidden;
326
+ }
327
+
328
+ .idb-bar-track i {
329
+ border-radius: inherit;
330
+ display: block;
331
+ height: 100%;
332
+ min-width: 8%;
333
+ transition: width 180ms ease;
334
+ }
335
+
336
+ .idb-bar-side:first-child i {
337
+ background: var(--idb-claim);
338
+ }
339
+
340
+ .idb-bar-side:last-child i {
341
+ background: var(--idb-pay);
342
+ margin-left: auto;
343
+ }
344
+
345
+ .idb-scale {
346
+ color: var(--idb-gold);
347
+ font-size: 1.55rem;
348
+ font-weight: 800;
349
+ }
350
+
351
+ .idb-result-grid {
352
+ display: grid;
353
+ gap: 0.65rem;
354
+ grid-template-columns: repeat(2, minmax(0, 1fr));
355
+ }
356
+
357
+ .idb-result-grid > div {
358
+ background: var(--idb-surface);
359
+ border: 1px solid var(--idb-edge);
360
+ border-radius: 0.75rem;
361
+ display: grid;
362
+ gap: 0.35rem;
363
+ padding: 0.8rem;
364
+ }
365
+
366
+ .idb-result-grid strong {
367
+ font-size: 1.08rem;
368
+ }
369
+
370
+ .idb-result-grid .idb-emphasis {
371
+ background: var(--idb-claim-soft);
372
+ border-color: var(--idb-claim);
373
+ }
374
+
375
+ .idb-result-note {
376
+ margin: 0;
377
+ }
378
+
379
+ .idb-error-summary {
380
+ background: var(--idb-pay-soft);
381
+ border: 1px solid var(--idb-pay);
382
+ border-radius: 0.65rem;
383
+ color: var(--idb-ink);
384
+ margin: 0;
385
+ padding: 0.7rem 0.8rem;
386
+ }
387
+
388
+ .idb-error-summary[hidden] {
389
+ display: none;
390
+ }
391
+
392
+ .idb-privacy,
393
+ .idb-method {
394
+ margin: 0;
395
+ }
396
+
397
+ .idb-method summary {
398
+ cursor: pointer;
399
+ font-weight: 800;
400
+ }
401
+
402
+ .idb-method p {
403
+ margin: 0.65rem 0 0;
404
+ }
405
+
406
+ @media (max-width: 42rem) {
407
+ .idb-card {
408
+ padding: 1rem;
409
+ }
410
+
411
+ .idb-inputs,
412
+ .idb-result-grid {
413
+ grid-template-columns: 1fr;
414
+ }
415
+
416
+ .idb-glance {
417
+ grid-template-columns: 1fr;
418
+ }
419
+
420
+ .idb-glance > div + div {
421
+ border-left: 0;
422
+ border-top: 1px solid var(--idb-edge);
423
+ }
424
+ }
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { calculateInsuranceDeductibleBreakEven, validateInsuranceInput, type InsuranceDeductibleInput } from './logic';
3
+
4
+ const baseInput: InsuranceDeductibleInput = { currency: 'USD', damageCost: 2500, deductible: 500, annualPremium: 1200, premiumIncreasePercent: 10, surchargeYears: 3 };
5
+
6
+ describe('calculateInsuranceDeductibleBreakEven', () => {
7
+ it('compares a claim with paying the full damage cost', () => {
8
+ const result = calculateInsuranceDeductibleBreakEven(baseInput);
9
+ expect(result).toMatchObject({ claimCost: 860, payYourselfCost: 2500, premiumSurcharge: 360, insurerShare: 2000, recommendation: 'claim', breakEvenDamage: 860 });
10
+ });
11
+
12
+ it('recommends paying yourself when the damage is below break even', () => {
13
+ const result = calculateInsuranceDeductibleBreakEven({ ...baseInput, damageCost: 700 });
14
+ expect(result?.recommendation).toBe('payYourself');
15
+ expect(result?.claimCost).toBe(860);
16
+ });
17
+
18
+ it('recognizes the exact break-even amount', () => {
19
+ const result = calculateInsuranceDeductibleBreakEven({ ...baseInput, damageCost: 860 });
20
+ expect(result?.recommendation).toBe('breakEven');
21
+ expect(result?.difference).toBe(0);
22
+ });
23
+
24
+ it('rejects invalid ranges and impossible values', () => {
25
+ const invalid = { ...baseInput, damageCost: 0, premiumIncreasePercent: 101, surchargeYears: 21 };
26
+ expect(Object.keys(validateInsuranceInput(invalid))).toEqual(['damageCost', 'premiumIncreasePercent', 'surchargeYears']);
27
+ expect(calculateInsuranceDeductibleBreakEven(invalid)).toBeNull();
28
+ });
29
+
30
+ it('handles a deductible larger than the damage', () => {
31
+ const result = calculateInsuranceDeductibleBreakEven({ ...baseInput, damageCost: 300, deductible: 500, premiumIncreasePercent: 0 });
32
+ expect(result).toMatchObject({ insurerShare: 0, claimCost: 300, recommendation: 'breakEven' });
33
+ });
34
+
35
+ it('accepts the documented upper bounds without losing a finite result', () => {
36
+ const result = calculateInsuranceDeductibleBreakEven({ currency: 'USD', damageCost: 1_000_000_000_000, deductible: 1_000_000_000_000, annualPremium: 1_000_000_000_000, premiumIncreasePercent: 100, surchargeYears: 20 });
37
+ expect(result?.claimCost).toBe(21_000_000_000_000);
38
+ expect(result?.payYourselfCost).toBe(1_000_000_000_000);
39
+ });
40
+ });
@@ -0,0 +1,72 @@
1
+ import { isInsuranceCurrencyCode, type InsuranceCurrencyCode } from './currency';
2
+
3
+ export interface InsuranceDeductibleInput {
4
+ currency: string;
5
+ damageCost: number;
6
+ deductible: number;
7
+ annualPremium: number;
8
+ premiumIncreasePercent: number;
9
+ surchargeYears: number;
10
+ }
11
+
12
+ export type InsuranceRecommendation = 'claim' | 'payYourself' | 'breakEven';
13
+
14
+ export interface InsuranceValidationErrors {
15
+ currency?: string;
16
+ damageCost?: string;
17
+ deductible?: string;
18
+ annualPremium?: string;
19
+ premiumIncreasePercent?: string;
20
+ surchargeYears?: string;
21
+ }
22
+
23
+ export interface InsuranceDeductibleResult {
24
+ currency: InsuranceCurrencyCode;
25
+ damageCost: number;
26
+ deductible: number;
27
+ annualPremium: number;
28
+ premiumIncreasePercent: number;
29
+ surchargeYears: number;
30
+ premiumSurcharge: number;
31
+ insurerShare: number;
32
+ claimCost: number;
33
+ payYourselfCost: number;
34
+ difference: number;
35
+ breakEvenDamage: number;
36
+ recommendation: InsuranceRecommendation;
37
+ }
38
+
39
+ const roundMoney = (value: number): number => Number(value.toFixed(2));
40
+ const isMoney = (value: number): boolean => Number.isFinite(value) && value >= 0 && value <= 1_000_000_000_000;
41
+
42
+ export function validateInsuranceInput(input: InsuranceDeductibleInput): InsuranceValidationErrors {
43
+ const errors: InsuranceValidationErrors = {};
44
+ const currency = input.currency.trim().toUpperCase();
45
+ const addError = (key: keyof InsuranceValidationErrors, invalid: boolean): void => { if (invalid) errors[key] = key; };
46
+ addError('currency', !isInsuranceCurrencyCode(currency));
47
+ addError('damageCost', !Number.isFinite(input.damageCost) || input.damageCost <= 0 || input.damageCost > 1_000_000_000_000);
48
+ addError('deductible', !isMoney(input.deductible));
49
+ addError('annualPremium', !isMoney(input.annualPremium));
50
+ addError('premiumIncreasePercent', !Number.isFinite(input.premiumIncreasePercent) || input.premiumIncreasePercent < 0 || input.premiumIncreasePercent > 100);
51
+ addError('surchargeYears', !Number.isFinite(input.surchargeYears) || input.surchargeYears <= 0 || input.surchargeYears > 20);
52
+ return errors;
53
+ }
54
+
55
+ const recommendationFor = (difference: number): InsuranceRecommendation => {
56
+ if (difference > 0.005) return 'claim';
57
+ if (difference < -0.005) return 'payYourself';
58
+ return 'breakEven';
59
+ };
60
+
61
+ export function calculateInsuranceDeductibleBreakEven(input: InsuranceDeductibleInput): InsuranceDeductibleResult | null {
62
+ const errors = validateInsuranceInput(input);
63
+ if (Object.keys(errors).length > 0) return null;
64
+ const currency = input.currency.trim().toUpperCase() as InsuranceCurrencyCode;
65
+ const premiumSurcharge = roundMoney(input.annualPremium * input.premiumIncreasePercent / 100 * input.surchargeYears);
66
+ const insurerShare = roundMoney(Math.max(0, input.damageCost - input.deductible));
67
+ const claimCost = roundMoney(Math.min(input.damageCost, input.deductible) + premiumSurcharge);
68
+ const payYourselfCost = roundMoney(input.damageCost);
69
+ const difference = roundMoney(payYourselfCost - claimCost);
70
+ const breakEvenDamage = roundMoney(input.deductible + premiumSurcharge);
71
+ return { currency, damageCost: payYourselfCost, deductible: roundMoney(input.deductible), annualPremium: roundMoney(input.annualPremium), premiumIncreasePercent: input.premiumIncreasePercent, surchargeYears: input.surchargeYears, premiumSurcharge, insurerShare, claimCost, payYourselfCost, difference, breakEvenDamage, recommendation: recommendationFor(difference) };
72
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { insuranceDeductibleBreakEvenCalculator } from './entry';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props { locale?: KnownLocale; }
7
+ const { locale = 'en' } = Astro.props;
8
+ const content = await insuranceDeductibleBreakEvenCalculator.i18n[locale]?.() ?? await insuranceDeductibleBreakEvenCalculator.i18n.en?.();
9
+ ---
10
+
11
+ {content?.seo && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,33 @@
1
+ export interface InsuranceDeductibleBreakEvenCalculatorUI extends Record<string, string> {
2
+ labelDamageCost: string;
3
+ labelDeductible: string;
4
+ labelAnnualPremium: string;
5
+ labelPremiumIncrease: string;
6
+ labelSurchargeYears: string;
7
+ labelCurrency: string;
8
+ labelClaimRoute: string;
9
+ labelPayYourselfRoute: string;
10
+ labelClaimCost: string;
11
+ labelPayYourselfCost: string;
12
+ labelPremiumSurcharge: string;
13
+ labelInsurerShare: string;
14
+ labelBreakEvenDamage: string;
15
+ labelDifference: string;
16
+ labelRecommendation: string;
17
+ labelClaimRecommended: string;
18
+ labelPayYourselfRecommended: string;
19
+ labelBreakEvenRecommendation: string;
20
+ labelVisual: string;
21
+ labelReset: string;
22
+ labelCopy: string;
23
+ labelCopied: string;
24
+ labelCopyFailed: string;
25
+ labelInvalidInput: string;
26
+ labelMethodTitle: string;
27
+ labelMethodText: string;
28
+ labelPrivacyNote: string;
29
+ labelAmountPlaceholder: string;
30
+ labelPercentPlaceholder: string;
31
+ labelYearsPlaceholder: string;
32
+ labelApproximateRates: string;
33
+ }
package/src/tools.ts CHANGED
@@ -25,5 +25,6 @@ import { SUBSCRIPTION_COST_ANNUALIZER_TOOL } from './tool/subscriptionCostAnnual
25
25
  import { LOAN_TO_INCOME_RATIO_TOOL } from './tool/loanToIncomeRatio';
26
26
  import { RENTAL_DEPOSIT_RETURN_TOOL } from './tool/rentalDepositReturn';
27
27
  import { CAPITAL_GAINS_TAX_SCENARIO_CALCULATOR_TOOL } from './tool/capitalGainsTaxScenarioCalculator';
28
+ import { INSURANCE_DEDUCTIBLE_BREAK_EVEN_CALCULATOR_TOOL } from './tool/insuranceDeductibleBreakEvenCalculator';
28
29
 
29
- export const ALL_TOOLS: ToolDefinition[] = [COMPOUND_INTEREST_TOOL, FINANCIAL_FREEDOM_TOOL, SAVINGS_RATE_TOOL, PROFITABILITY_TOOL, MORTGAGE_TOOL, INFLATION_TOOL, PERCENTAGE_CALCULATOR_TOOL, LATE_INTEREST_TOOL, IBAN_BIC_SWIFT_TOOL, RENT_INCREASE_TOOL, LOTTERY_OPTIMIZER_TOOL, COURT_FEE_CALCULATOR_TOOL, LEGAL_INTEREST_RATE_TOOL, FIRE_CALCULATOR_TOOL, DEBT_SNOWBALL_TOOL, REVOLVING_CARD_CALCULATOR_TOOL, PESETA_VALUE_TOOL, SALARY_EMPLOYER_COST_TOOL, DIVIDEND_YIELD_TOOL, MORTGAGE_EXTRA_PAYMENT_PLANNER_TOOL, INFLATION_PURCHASING_POWER_TOOL, SUBSCRIPTION_COST_ANNUALIZER_TOOL, LOAN_TO_INCOME_RATIO_TOOL, RENTAL_DEPOSIT_RETURN_TOOL, CAPITAL_GAINS_TAX_SCENARIO_CALCULATOR_TOOL];
30
+ export const ALL_TOOLS: ToolDefinition[] = [COMPOUND_INTEREST_TOOL, FINANCIAL_FREEDOM_TOOL, SAVINGS_RATE_TOOL, PROFITABILITY_TOOL, MORTGAGE_TOOL, INFLATION_TOOL, PERCENTAGE_CALCULATOR_TOOL, LATE_INTEREST_TOOL, IBAN_BIC_SWIFT_TOOL, RENT_INCREASE_TOOL, LOTTERY_OPTIMIZER_TOOL, COURT_FEE_CALCULATOR_TOOL, LEGAL_INTEREST_RATE_TOOL, FIRE_CALCULATOR_TOOL, DEBT_SNOWBALL_TOOL, REVOLVING_CARD_CALCULATOR_TOOL, PESETA_VALUE_TOOL, SALARY_EMPLOYER_COST_TOOL, DIVIDEND_YIELD_TOOL, MORTGAGE_EXTRA_PAYMENT_PLANNER_TOOL, INFLATION_PURCHASING_POWER_TOOL, SUBSCRIPTION_COST_ANNUALIZER_TOOL, LOAN_TO_INCOME_RATIO_TOOL, RENTAL_DEPOSIT_RETURN_TOOL, CAPITAL_GAINS_TAX_SCENARIO_CALCULATOR_TOOL, INSURANCE_DEDUCTIBLE_BREAK_EVEN_CALCULATOR_TOOL];