@jjlmoya/utils-finance 1.1.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 (133) hide show
  1. package/package.json +64 -0
  2. package/src/category/i18n/en.ts +159 -0
  3. package/src/category/i18n/es.ts +159 -0
  4. package/src/category/i18n/fr.ts +159 -0
  5. package/src/category/index.ts +24 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +32 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +39 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +23 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/compoundInterest/bibliography.astro +14 -0
  25. package/src/tool/compoundInterest/component.astro +697 -0
  26. package/src/tool/compoundInterest/i18n/en.ts +212 -0
  27. package/src/tool/compoundInterest/i18n/es.ts +212 -0
  28. package/src/tool/compoundInterest/i18n/fr.ts +212 -0
  29. package/src/tool/compoundInterest/index.ts +34 -0
  30. package/src/tool/compoundInterest/logic.ts +40 -0
  31. package/src/tool/compoundInterest/seo.astro +14 -0
  32. package/src/tool/compoundInterest/ui.ts +19 -0
  33. package/src/tool/courtFeeCalculator/bibliography.astro +14 -0
  34. package/src/tool/courtFeeCalculator/component.astro +427 -0
  35. package/src/tool/courtFeeCalculator/i18n/en.ts +268 -0
  36. package/src/tool/courtFeeCalculator/i18n/es.ts +268 -0
  37. package/src/tool/courtFeeCalculator/i18n/fr.ts +268 -0
  38. package/src/tool/courtFeeCalculator/index.ts +33 -0
  39. package/src/tool/courtFeeCalculator/logic.ts +86 -0
  40. package/src/tool/courtFeeCalculator/seo.astro +14 -0
  41. package/src/tool/courtFeeCalculator/ui.ts +31 -0
  42. package/src/tool/debtSnowball/bibliography.astro +14 -0
  43. package/src/tool/debtSnowball/component.astro +1052 -0
  44. package/src/tool/debtSnowball/i18n/en.ts +288 -0
  45. package/src/tool/debtSnowball/i18n/es.ts +288 -0
  46. package/src/tool/debtSnowball/i18n/fr.ts +288 -0
  47. package/src/tool/debtSnowball/index.ts +37 -0
  48. package/src/tool/debtSnowball/logic.ts +156 -0
  49. package/src/tool/debtSnowball/seo.astro +14 -0
  50. package/src/tool/debtSnowball/ui.ts +49 -0
  51. package/src/tool/fireCalculator/bibliography.astro +14 -0
  52. package/src/tool/fireCalculator/component.astro +689 -0
  53. package/src/tool/fireCalculator/i18n/en.ts +261 -0
  54. package/src/tool/fireCalculator/i18n/es.ts +261 -0
  55. package/src/tool/fireCalculator/i18n/fr.ts +261 -0
  56. package/src/tool/fireCalculator/index.ts +33 -0
  57. package/src/tool/fireCalculator/logic.ts +108 -0
  58. package/src/tool/fireCalculator/seo.astro +14 -0
  59. package/src/tool/fireCalculator/ui.ts +33 -0
  60. package/src/tool/ibanBicSwiftConverter/bibliography.astro +14 -0
  61. package/src/tool/ibanBicSwiftConverter/component.astro +581 -0
  62. package/src/tool/ibanBicSwiftConverter/i18n/en.ts +167 -0
  63. package/src/tool/ibanBicSwiftConverter/i18n/es.ts +216 -0
  64. package/src/tool/ibanBicSwiftConverter/i18n/fr.ts +167 -0
  65. package/src/tool/ibanBicSwiftConverter/index.ts +33 -0
  66. package/src/tool/ibanBicSwiftConverter/logic.ts +101 -0
  67. package/src/tool/ibanBicSwiftConverter/seo.astro +14 -0
  68. package/src/tool/ibanBicSwiftConverter/ui.ts +17 -0
  69. package/src/tool/inflation/bibliography.astro +14 -0
  70. package/src/tool/inflation/component.astro +400 -0
  71. package/src/tool/inflation/i18n/en.ts +301 -0
  72. package/src/tool/inflation/i18n/es.ts +301 -0
  73. package/src/tool/inflation/i18n/fr.ts +301 -0
  74. package/src/tool/inflation/index.ts +34 -0
  75. package/src/tool/inflation/logic.ts +92 -0
  76. package/src/tool/inflation/seo.astro +14 -0
  77. package/src/tool/inflation/ui.ts +17 -0
  78. package/src/tool/lateInterest/bibliography.astro +14 -0
  79. package/src/tool/lateInterest/component.astro +655 -0
  80. package/src/tool/lateInterest/i18n/en.ts +255 -0
  81. package/src/tool/lateInterest/i18n/es.ts +224 -0
  82. package/src/tool/lateInterest/i18n/fr.ts +224 -0
  83. package/src/tool/lateInterest/index.ts +34 -0
  84. package/src/tool/lateInterest/logic.ts +89 -0
  85. package/src/tool/lateInterest/seo.astro +14 -0
  86. package/src/tool/lateInterest/ui.ts +33 -0
  87. package/src/tool/legalInterestRate/bibliography.astro +14 -0
  88. package/src/tool/legalInterestRate/component.astro +650 -0
  89. package/src/tool/legalInterestRate/i18n/en.ts +159 -0
  90. package/src/tool/legalInterestRate/i18n/es.ts +159 -0
  91. package/src/tool/legalInterestRate/i18n/fr.ts +159 -0
  92. package/src/tool/legalInterestRate/index.ts +33 -0
  93. package/src/tool/legalInterestRate/logic.ts +29 -0
  94. package/src/tool/legalInterestRate/seo.astro +14 -0
  95. package/src/tool/legalInterestRate/ui.ts +23 -0
  96. package/src/tool/lotteryOptimizer/bibliography.astro +14 -0
  97. package/src/tool/lotteryOptimizer/component.astro +863 -0
  98. package/src/tool/lotteryOptimizer/i18n/en.ts +188 -0
  99. package/src/tool/lotteryOptimizer/i18n/es.ts +281 -0
  100. package/src/tool/lotteryOptimizer/i18n/fr.ts +188 -0
  101. package/src/tool/lotteryOptimizer/index.ts +33 -0
  102. package/src/tool/lotteryOptimizer/logic.ts +133 -0
  103. package/src/tool/lotteryOptimizer/seo.astro +14 -0
  104. package/src/tool/lotteryOptimizer/ui.ts +33 -0
  105. package/src/tool/mortgage/bibliography.astro +14 -0
  106. package/src/tool/mortgage/component.astro +1030 -0
  107. package/src/tool/mortgage/i18n/en.ts +227 -0
  108. package/src/tool/mortgage/i18n/es.ts +227 -0
  109. package/src/tool/mortgage/i18n/fr.ts +227 -0
  110. package/src/tool/mortgage/index.ts +34 -0
  111. package/src/tool/mortgage/logic.ts +118 -0
  112. package/src/tool/mortgage/seo.astro +14 -0
  113. package/src/tool/mortgage/ui.ts +35 -0
  114. package/src/tool/percentageCalculator/bibliography.astro +14 -0
  115. package/src/tool/percentageCalculator/component.astro +640 -0
  116. package/src/tool/percentageCalculator/i18n/en.ts +233 -0
  117. package/src/tool/percentageCalculator/i18n/es.ts +233 -0
  118. package/src/tool/percentageCalculator/i18n/fr.ts +233 -0
  119. package/src/tool/percentageCalculator/index.ts +34 -0
  120. package/src/tool/percentageCalculator/logic.ts +48 -0
  121. package/src/tool/percentageCalculator/seo.astro +14 -0
  122. package/src/tool/percentageCalculator/ui.ts +30 -0
  123. package/src/tool/rentIncreaseCalculator/bibliography.astro +14 -0
  124. package/src/tool/rentIncreaseCalculator/component.astro +587 -0
  125. package/src/tool/rentIncreaseCalculator/i18n/en.ts +159 -0
  126. package/src/tool/rentIncreaseCalculator/i18n/es.ts +220 -0
  127. package/src/tool/rentIncreaseCalculator/i18n/fr.ts +159 -0
  128. package/src/tool/rentIncreaseCalculator/index.ts +33 -0
  129. package/src/tool/rentIncreaseCalculator/logic.ts +43 -0
  130. package/src/tool/rentIncreaseCalculator/seo.astro +14 -0
  131. package/src/tool/rentIncreaseCalculator/ui.ts +19 -0
  132. package/src/tools.ts +16 -0
  133. package/src/types.ts +74 -0
@@ -0,0 +1,288 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { DebtSnowballUI } from '../ui';
4
+
5
+ const slug = 'calculatrice-boule-de-neige-dette';
6
+ const title = 'Calculatrice Méthode Boule de Neige: Plan de Remboursement de Dettes 2026';
7
+ const description =
8
+ 'Calculez votre date de liberté financière en utilisant la méthode de la boule de neige. Organisez vos dettes de la plus petite à la plus grande et visualisez votre plan de paiement mensuel gratuitement.';
9
+
10
+ const faqData = [
11
+ {
12
+ question: 'Qu\'est-ce que la méthode de la boule de neige?',
13
+ answer:
14
+ 'C\'est une stratégie de remboursement de dettes popularisée par Dave Ramsey qui consiste à payer les dettes en ordre du solde le plus petit au plus grand, indépendamment des taux d\'intérêt. Elle se concentre sur la victoire psychologique d\'éliminer rapidement les petits comptes pour gagner en motivation.',
15
+ },
16
+ {
17
+ question: 'Pourquoi ne pas classer par taux d\'intérêt (Avalanche)?',
18
+ answer:
19
+ 'Mathématiquement, payer le taux le plus élevé en premier économise plus d\'argent. Cependant, beaucoup de gens abandonnent car ils ne voient pas de résultats immédiats. La Boule de Neige priorise le comportement et la motivation: voir une dette disparaître rapidement vous donne l\'énergie de continuer.',
20
+ },
21
+ {
22
+ question: 'Dois-je avoir des économies avant de commencer le plan?',
23
+ answer:
24
+ 'Il est recommandé d\'avoir un "Fonds d\'Urgence Initiale" (environ 1 000€) avant d\'attaquer les dettes. Cela évite de devoir recourir à nouveau aux cartes de crédit si une dépense imprévue survient, cassant votre séquence de progrès.',
25
+ },
26
+ {
27
+ question: 'Quelles dettes dois-je inclure dans la calculatrice?',
28
+ answer:
29
+ 'Toutes les dettes de consommation: cartes de crédit, prêts personnels, dettes familiales, prêts automobiles, factures impayées. Les hypothèques sont généralement laissées pour une phase ultérieure en raison de leur volume important.',
30
+ },
31
+ {
32
+ question: 'Que faire si je reçois un revenu supplémentaire inattendu?',
33
+ answer:
34
+ 'Toute injection de capital (bonus, loterie, salaire supplémentaire) doit aller entièrement à la dette que vous attaquez actuellement. Cela réduit drastiquement le temps total de votre plan de liberté financière.',
35
+ },
36
+ ];
37
+
38
+ const howToData = [
39
+ {
40
+ name: 'Listez vos dettes',
41
+ text: 'Écrivez toutes vos dettes en indiquant le solde total impayé et le paiement minimum mensuel que vous effectuez actuellement pour chacune. Ne vous préoccupez pas des intérêts pour le moment.',
42
+ },
43
+ {
44
+ name: 'Définissez votre budget supplémentaire',
45
+ text: 'Calculez combien d\'argent supplémentaire vous pouvez allouer chaque mois en plus des paiements minimums. Même 20€ par mois peuvent faire une différence dans l\'effet boule de neige.',
46
+ },
47
+ {
48
+ name: 'Ordonnez et priorisez',
49
+ text: 'La calculatrice ordonnera automatiquement du solde le plus petit au plus grand. Payez le minimum sur tous sauf le plus petit. Mettez tout votre argent supplémentaire sur celui-ci.',
50
+ },
51
+ {
52
+ name: 'Exécutez la cascade',
53
+ text: 'Une fois que vous avez payé la plus petite dette, prenez tout l\'argent que vous y allouviez (son minimum + l\'extra) et ajoutez-le à la prochaine dette de la liste. Répétez jusqu\'à être libre.',
54
+ },
55
+ ];
56
+
57
+ const bibliographyData = [
58
+ {
59
+ name: 'Investopedia — Debt Snowball vs. Debt Avalanche',
60
+ url: 'https://www.investopedia.com/articles/personal-finance/080716/debt-avalanche-vs-debt-snowball-which-best-you.asp',
61
+ },
62
+ {
63
+ name: 'Harvard Business Review — Research on Debt Payoff Strategies',
64
+ url: 'https://hbr.org/2016/12/research-the-best-strategy-for-paying-off-credit-card-debt',
65
+ },
66
+ ];
67
+
68
+ const faqSchema: WithContext<FAQPage> = {
69
+ '@context': 'https://schema.org',
70
+ '@type': 'FAQPage',
71
+ mainEntity: faqData.map((item) => ({
72
+ '@type': 'Question',
73
+ name: item.question,
74
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
75
+ })),
76
+ };
77
+
78
+ const howToSchema: WithContext<HowTo> = {
79
+ '@context': 'https://schema.org',
80
+ '@type': 'HowTo',
81
+ name: title,
82
+ description,
83
+ step: howToData.map((step, i) => ({
84
+ '@type': 'HowToStep',
85
+ position: i + 1,
86
+ name: step.name,
87
+ text: step.text,
88
+ })),
89
+ };
90
+
91
+ const appSchema: WithContext<SoftwareApplication> = {
92
+ '@context': 'https://schema.org',
93
+ '@type': 'SoftwareApplication',
94
+ name: title,
95
+ description,
96
+ applicationCategory: 'FinanceApplication',
97
+ operatingSystem: 'All',
98
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
99
+ inLanguage: 'fr',
100
+ };
101
+
102
+ export const content: ToolLocaleContent<DebtSnowballUI> = {
103
+ slug,
104
+ title,
105
+ description,
106
+ faqTitle: 'Questions Fréquemment Posées',
107
+ faq: faqData,
108
+ bibliographyTitle: 'Sources et Références',
109
+ bibliography: bibliographyData,
110
+ howTo: howToData,
111
+ schemas: [faqSchema, howToSchema, appSchema],
112
+ seo: [
113
+ {
114
+ type: 'title',
115
+ text: 'Calculatrice de Dette avec la Méthode Boule de Neige: Guide 2026',
116
+ level: 2,
117
+ },
118
+ {
119
+ type: 'paragraph',
120
+ html: 'Vivre avec des dettes, c\'est comme essayer de courir un marathon avec un sac à dos rempli de pierres. La <strong>méthode de la boule de neige</strong>, popularisée par les experts en finances personnelles, s\'est avérée être l\'une des stratégies les plus efficaces pour retrouver la liberté financière. Elle ne repose pas sur l\'efficacité mathématique, mais sur la puissante <strong>base psychologique du comportement humain</strong>.',
121
+ },
122
+ {
123
+ type: 'title',
124
+ text: 'Qu\'est-ce que la Méthode de la Boule de Neige?',
125
+ level: 3,
126
+ },
127
+ {
128
+ type: 'paragraph',
129
+ html: 'La méthode de la boule de neige est une stratégie de réduction de dettes où vous remboursez vos obligations en ordre du <strong>solde le plus petit au plus grand</strong>, indépendamment de leurs taux d\'intérêt. Pendant que vous effectuez les paiements minimums sur toutes vos dettes, vous allouez chaque euro supplémentaire que vous pouvez économiser au solde le plus petit.',
130
+ },
131
+ {
132
+ type: 'paragraph',
133
+ html: 'Une fois que cette première dette disparaît, tout l\'argent que vous lui allouuviez va vers la prochaine plus petite dette. Cet effet crée un momentum similaire à une petite boule de neige qui roule en bas d\'une colline, devenant plus grande et plus rapide à chaque tour.',
134
+ },
135
+ {
136
+ type: 'title',
137
+ text: 'Psychologie vs. Mathématiques: Pourquoi ça marche?',
138
+ level: 3,
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'Si vous parlez à un financier pur, il vous dira que la <strong>Méthode de l\'Avalanche</strong> est supérieure car vous économisez plus d\'argent en intérêts. Et techniquement, ils ont raison. Cependant, la dette n\'est pas un problème de mathématiques; c\'est un problème d\'<strong>habitudes et de comportement</strong>.',
143
+ },
144
+ {
145
+ type: 'list',
146
+ items: [
147
+ '<strong>Victoires rapides:</strong> En éliminant la plus petite dette en seulement quelques mois, vous obtenez une libération de dopamine qui vous motive à continuer.',
148
+ '<strong>Simplification mentale:</strong> Passer de 7 factures mensuelles à 6 réduit le stress et la complexité de votre vie financière.',
149
+ '<strong>Motivation soutenue:</strong> Le succès précoce vous donne l\'énergie nécessaire pour affronter les plus grandes dettes qui viendront plus tard.',
150
+ ],
151
+ },
152
+ {
153
+ type: 'title',
154
+ text: 'Boule de Neige vs. Avalanche: Différences clés',
155
+ level: 3,
156
+ },
157
+ {
158
+ type: 'paragraph',
159
+ html: 'Notre outil vous permet de comparer les deux scénarios en temps réel pour que vous décidiez quel plan convient le mieux à votre profil:',
160
+ },
161
+ {
162
+ type: 'comparative',
163
+ columns: 2,
164
+ items: [
165
+ {
166
+ title: 'Méthode Avalanche',
167
+ description: 'Priorise le taux d\'intérêt le plus élevé.',
168
+ points: [
169
+ 'Vous économisez le maximum d\'argent sur les intérêts bancaires',
170
+ 'Il peut prendre longtemps pour sentir les progrès',
171
+ 'Si la dette la plus chère est très importante, le découragement arrive plus tôt',
172
+ 'Mathématiquement optimal',
173
+ ],
174
+ },
175
+ {
176
+ title: 'Méthode Boule de Neige',
177
+ description: 'Priorise le solde le plus petit.',
178
+ points: [
179
+ 'Vous éliminez les comptes de votre liste dès que possible',
180
+ 'Génère un renforcement positif immédiat',
181
+ 'Taux de réussite du plan plus élevé',
182
+ 'Psychologiquement gratifiant',
183
+ ],
184
+ },
185
+ ],
186
+ },
187
+ {
188
+ type: 'title',
189
+ text: 'Comment Utiliser la Calculatrice de Dette',
190
+ level: 3,
191
+ },
192
+ {
193
+ type: 'paragraph',
194
+ html: 'Pour obtenir un plan de paiement précis, suivez ces étapes structurées dans l\'outil:',
195
+ },
196
+ {
197
+ type: 'list',
198
+ items: [
199
+ '<strong>Cartographie des dettes:</strong> Entrez le nom, le solde impayé actuel et le paiement minimum mensuel pour chaque prêt ou carte.',
200
+ '<strong>Ajustement du budget:</strong> Définissez votre "Budget Supplémentaire". C\'est la somme mensuelle que vous pouvez économiser en plus des paiements minimums.',
201
+ '<strong>Simulation de capital:</strong> Utilisez l\'option d\'injection de capital pour voir comment un revenu inattendu (comme un bonus) raccourcit votre calendrier.',
202
+ ],
203
+ },
204
+ {
205
+ type: 'paragraph',
206
+ html: '<strong>Formule d\'amortissement:</strong> Solde Final = Solde Initial + Intérêts Mensuels - (Paiement Minimum + Budget Supplémentaire)',
207
+ },
208
+ {
209
+ type: 'title',
210
+ text: 'Conseils pour Accélérer Votre Liberté Financière',
211
+ level: 3,
212
+ },
213
+ {
214
+ type: 'paragraph',
215
+ html: 'La calculatrice vous montre une date estimée basée sur vos données actuelles, mais cette date n\'est pas gravée dans le marbre:',
216
+ },
217
+ {
218
+ type: 'list',
219
+ items: [
220
+ '<strong>Passez en revue vos abonnements:</strong> Souvent, cet argent supplémentaire de 50€ que vous besoin est caché dans des services que vous n\'utilisez pas.',
221
+ '<strong>Gelsez vos cartes:</strong> Vous ne pouvez pas sortir d\'un trou si vous continuez à creuser. Pendant le plan, évitez de contracter de nouvelles dettes.',
222
+ '<strong>Fonds d\'urgence:</strong> Ayez au moins 1 000€ économisés avant de commencer. Cela empêche une dépense inattendue de casser votre plan de paiement.',
223
+ ],
224
+ },
225
+ {
226
+ type: 'paragraph',
227
+ html: '<strong>Souvenez-vous:</strong> La liberté financière est 20% de connaissance et 80% de comportement. Le jour où vous verrez "0" sur votre solde final sera le jour où vous retrouverez le contrôle total de votre temps et votre argent.',
228
+ },
229
+ {
230
+ type: 'title',
231
+ text: 'Conclusion et Prochaines Étapes',
232
+ level: 3,
233
+ },
234
+ {
235
+ type: 'paragraph',
236
+ html: 'La <strong>calculatrice de la méthode boule de neige</strong> est un outil de planification fondamental. Le vrai travail se fait dans votre vie quotidienne, dans les décisions que vous prenez à chaque achat. Nous vous recommandons de télécharger votre plan au format CSV et de le poster quelque part de visible pour rester concentré sur votre objectif final: être sans dettes.',
237
+ },
238
+ ],
239
+ ui: {
240
+ labelTitle: 'Liberté totale',
241
+ labelDescription: 'Entrez en mode liberté financière. Utilisez la méthode psychologiquement la plus efficace pour éliminer vos dettes.',
242
+ labelExtraBudget: 'BUDGET SUPPLÉMENTAIRE MENSUEL',
243
+ labelExtraBudgetHelp: 'Argent supplémentaire en plus des paiements minimums.',
244
+ labelSnowballMethod: 'BOULE DE NEIGE',
245
+ labelAvalancheMethod: 'AVALANCHE',
246
+ labelAddNewDebt: 'AJOUTER UNE NOUVELLE DETTE',
247
+ labelDebtName: 'Nom',
248
+ labelDebtNamePlaceholder: 'Ex: Visa',
249
+ labelDebtBalance: 'COMBIEN VOUS DEVEZ',
250
+ labelDebtBalancePlaceholder: '0',
251
+ labelMinPayment: 'PAIEMENT MINIMUM',
252
+ labelInterestRate: 'TAUX D\'INTÉRÊT',
253
+ labelInterestHelp: 'ANNUEL',
254
+ labelAddButton: 'AJOUTER AU PLAN',
255
+ labelClearData: 'Effacer la configuration',
256
+ labelClearDataConfirm: 'Effacer le plan?',
257
+ labelDeleteDebt: 'Supprimer',
258
+ labelDebtInventory: 'Inventaire des Dettes',
259
+ labelFreedomDate: 'DATE DE LIBERTÉ FINANCIÈRE',
260
+ labelActiveMethod: 'MÉTHODE',
261
+ labelMonthsRemaining: 'MOIS RESTANTS',
262
+ labelTotalInterest: 'INTÉRÊT TOTAL',
263
+ labelTotalPaid: 'PAIEMENT TOTAL FINAL',
264
+ labelInterestSaved: 'INTÉRÊTS ÉCONOMISÉS',
265
+ labelYourStrategy: 'Votre Stratégie Étape par Étape',
266
+ labelStrategyHelp: 'Chaque étape montre votre paiement total quand c\'est son tour',
267
+ labelPriority: 'PRIORITÉ MAXIMALE',
268
+ labelStep: 'ÉTAPE',
269
+ labelAfterPaying: 'APRÈS PAIEMENT PRÉCÉDENT',
270
+ labelMonthlyPayment: 'Paiement mensuel',
271
+ labelDetailedAmortization: 'Amortissement Détaillé',
272
+ labelExportCSV: 'Exporter .CSV',
273
+ labelDate: 'Date',
274
+ labelStartingBalance: 'Solde Initial',
275
+ labelInterest: 'Intérêt',
276
+ labelAmortization: 'Amortissé',
277
+ labelTotalMonth: 'Total du Mois',
278
+ labelRemaining: 'Restant',
279
+ labelFree: 'LIBRE',
280
+ labelDebtInfinite: 'DETTE INFINIE',
281
+ labelInvalidInput: 'Indiquez le solde total et le paiement minimum',
282
+ labelEmptyStateTitle: 'Commencez votre plan',
283
+ labelEmptyStateDescription: 'Vos dettes n\'auront pas pour toujours. Ajoutez vos dettes pour visualiser votre chemin vers la liberté financière.',
284
+ currencySymbol: '€',
285
+ currencyCode: 'EUR',
286
+ currencyLocale: 'fr-FR',
287
+ },
288
+ };
@@ -0,0 +1,37 @@
1
+ import type { FinanceToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
+ import DebtSnowballComponent from './component.astro';
3
+ import DebtSnowballSEO from './seo.astro';
4
+ import DebtSnowballBibliography from './bibliography.astro';
5
+ import type { DebtSnowballUI } from './ui';
6
+ import { DebtSnowballLogic, type Debt, type SimulationResult, type ProjectionMonth } from './logic';
7
+
8
+ export type DebtSnowballLocaleContent = ToolLocaleContent<DebtSnowballUI>;
9
+ export type { Debt, SimulationResult, ProjectionMonth };
10
+
11
+ import { content as es } from './i18n/es';
12
+ import { content as en } from './i18n/en';
13
+ import { content as fr } from './i18n/fr';
14
+
15
+ export const debtSnowball: FinanceToolEntry<DebtSnowballUI> = {
16
+ id: 'bola-nieve-deuda',
17
+ icons: {
18
+ bg: 'mdi:chart-line',
19
+ fg: 'mdi:trending-up',
20
+ },
21
+ i18n: {
22
+ es: async () => es,
23
+ en: async () => en,
24
+ fr: async () => fr,
25
+ },
26
+ };
27
+
28
+ export { DebtSnowballComponent, DebtSnowballSEO, DebtSnowballBibliography };
29
+
30
+ export const DEBT_SNOWBALL_TOOL: ToolDefinition = {
31
+ entry: debtSnowball,
32
+ Component: DebtSnowballComponent,
33
+ SEOComponent: DebtSnowballSEO,
34
+ BibliographyComponent: DebtSnowballBibliography,
35
+ };
36
+
37
+ export const DebtSnowballLogicExport = DebtSnowballLogic;
@@ -0,0 +1,156 @@
1
+ export interface Debt {
2
+ id: string;
3
+ name: string;
4
+ balance: number;
5
+ minPayment: number;
6
+ rate: number;
7
+ }
8
+
9
+ interface DebtState extends Debt {
10
+ balance: number;
11
+ }
12
+
13
+ export interface SimulationResult {
14
+ proj: ProjectionMonth[];
15
+ mo: number;
16
+ totalI: number;
17
+ totalP: number;
18
+ isGrowing: boolean;
19
+ }
20
+
21
+ export interface ProjectionMonth {
22
+ mo: number;
23
+ iniB: number;
24
+ int: number;
25
+ princ: number;
26
+ total: number;
27
+ finB: number;
28
+ }
29
+
30
+ interface MonthParams {
31
+ current: DebtState[];
32
+ proj: ProjectionMonth[];
33
+ initialTotalCommitment: number;
34
+ mo: number;
35
+ }
36
+
37
+ export class DebtSnowballLogic {
38
+ static simulate(debts: Debt[], extra: number, method: 'snowball' | 'avalanche'): SimulationResult | null {
39
+ if (debts.length === 0) return null;
40
+ const current = this.initializeDebts(debts, method);
41
+ const initialTotalCommitment = debts.reduce((s, d) => s + d.minPayment, 0) + extra;
42
+ const result = { proj: [] as ProjectionMonth[], totalI: 0, totalP: 0, isGrowing: false, mo: 0 };
43
+
44
+ while (current.some((d) => d.balance > 0.01) && result.mo < 600) {
45
+ const monthI = this.processMonth({ current, proj: result.proj, initialTotalCommitment, mo: result.mo });
46
+ result.totalI += monthI;
47
+ this.checkGrowingDebt(result, current);
48
+ if (result.isGrowing && result.mo > 24) break;
49
+ result.totalP = result.proj[result.mo]?.total || result.totalP;
50
+ result.mo++;
51
+ }
52
+
53
+ return result;
54
+ }
55
+
56
+ private static checkGrowingDebt(result: { proj: ProjectionMonth[]; isGrowing: boolean; mo: number }, current: DebtState[]) {
57
+ const finB = current.reduce((s: number, d: DebtState) => s + d.balance, 0);
58
+ const iniB = result.proj[result.mo]?.iniB || 0;
59
+ result.isGrowing = finB >= iniB && result.mo > 1 && iniB > 0;
60
+ }
61
+
62
+ private static initializeDebts(debts: Debt[], method: 'snowball' | 'avalanche'): DebtState[] {
63
+ const current = JSON.parse(JSON.stringify(debts)).map((d: Debt) => ({
64
+ ...d,
65
+ balance: parseFloat(d.balance.toString()),
66
+ minPayment: parseFloat(d.minPayment.toString()),
67
+ rate: parseFloat(d.rate.toString()),
68
+ })) as DebtState[];
69
+
70
+ if (method === 'snowball') {
71
+ current.sort((a, b) => a.balance - b.balance);
72
+ } else {
73
+ current.sort((a, b) => b.rate - a.rate);
74
+ }
75
+ return current;
76
+ }
77
+
78
+ private static processMonth(params: MonthParams): number {
79
+ const { current, proj, initialTotalCommitment, mo } = params;
80
+ const iniB = current.reduce((s: number, d: DebtState) => s + d.balance, 0);
81
+ const monthI = this.applyInterestAndMinPayments(current);
82
+ const paidThisMonth = this.distributePayments(current, initialTotalCommitment);
83
+ const finB = current.reduce((s: number, d: DebtState) => s + d.balance, 0);
84
+
85
+ proj.push({
86
+ mo: mo + 1,
87
+ iniB,
88
+ int: monthI,
89
+ princ: paidThisMonth - monthI,
90
+ total: paidThisMonth,
91
+ finB: Math.max(0, finB),
92
+ });
93
+
94
+ return monthI;
95
+ }
96
+
97
+ private static applyInterestAndMinPayments(current: DebtState[]): number {
98
+ let monthI = 0;
99
+ current.forEach((d) => {
100
+ if (d.balance > 0) {
101
+ const i = d.balance * ((d.rate / 100) / 12);
102
+ d.balance += i;
103
+ monthI += i;
104
+ }
105
+ });
106
+ return monthI;
107
+ }
108
+
109
+ private static distributePayments(current: DebtState[], initialTotalCommitment: number): number {
110
+ let paidThisMonth = 0;
111
+ current.forEach((d) => {
112
+ if (d.balance > 0) {
113
+ const p = Math.min(d.balance, d.minPayment);
114
+ d.balance -= p;
115
+ paidThisMonth += p;
116
+ }
117
+ });
118
+
119
+ const availableExtra = initialTotalCommitment - paidThisMonth;
120
+ if (availableExtra > 0) {
121
+ const target = current.find((d) => d.balance > 0.01);
122
+ if (target) {
123
+ const extraPay = Math.min(target.balance, availableExtra);
124
+ target.balance -= extraPay;
125
+ paidThisMonth += extraPay;
126
+ }
127
+ }
128
+
129
+ return paidThisMonth;
130
+ }
131
+
132
+ static simulateNoExtra(debts: Debt[]): { totalI: number } | null {
133
+ if (!debts.length) return null;
134
+ const current = JSON.parse(JSON.stringify(debts));
135
+ let mo = 0;
136
+ let totalI = 0;
137
+
138
+ while (current.some((d: Debt) => d.balance > 0.01) && mo < 480) {
139
+ const iniB = current.reduce((s: number, d: Debt) => s + d.balance, 0);
140
+ current.forEach((d: Debt) => {
141
+ if (d.balance > 0) {
142
+ const i = d.balance * ((d.rate / 100) / 12);
143
+ d.balance += i;
144
+ totalI += i;
145
+ const p = Math.min(d.balance, d.minPayment);
146
+ d.balance -= p;
147
+ }
148
+ });
149
+ const finB = current.reduce((s: number, d: Debt) => s + d.balance, 0);
150
+ if (finB > iniB && mo > 24) break;
151
+ mo++;
152
+ }
153
+
154
+ return { totalI };
155
+ }
156
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { debtSnowball } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await debtSnowball.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+ <SEORenderer content={{ locale: locale as string, sections: content.seo }} />
@@ -0,0 +1,49 @@
1
+ export interface DebtSnowballUI {
2
+ labelTitle: string;
3
+ labelDescription: string;
4
+ labelExtraBudget: string;
5
+ labelExtraBudgetHelp: string;
6
+ labelSnowballMethod: string;
7
+ labelAvalancheMethod: string;
8
+ labelAddNewDebt: string;
9
+ labelDebtName: string;
10
+ labelDebtNamePlaceholder: string;
11
+ labelDebtBalance: string;
12
+ labelDebtBalancePlaceholder: string;
13
+ labelMinPayment: string;
14
+ labelInterestRate: string;
15
+ labelInterestHelp: string;
16
+ labelAddButton: string;
17
+ labelClearData: string;
18
+ labelClearDataConfirm: string;
19
+ labelDeleteDebt: string;
20
+ labelDebtInventory: string;
21
+ labelFreedomDate: string;
22
+ labelActiveMethod: string;
23
+ labelMonthsRemaining: string;
24
+ labelTotalInterest: string;
25
+ labelTotalPaid: string;
26
+ labelInterestSaved: string;
27
+ labelYourStrategy: string;
28
+ labelStrategyHelp: string;
29
+ labelPriority: string;
30
+ labelStep: string;
31
+ labelAfterPaying: string;
32
+ labelMonthlyPayment: string;
33
+ labelDetailedAmortization: string;
34
+ labelExportCSV: string;
35
+ labelDate: string;
36
+ labelStartingBalance: string;
37
+ labelInterest: string;
38
+ labelAmortization: string;
39
+ labelTotalMonth: string;
40
+ labelRemaining: string;
41
+ labelFree: string;
42
+ labelDebtInfinite: string;
43
+ labelInvalidInput: string;
44
+ labelEmptyStateTitle: string;
45
+ labelEmptyStateDescription: string;
46
+ currencySymbol: string;
47
+ currencyCode: string;
48
+ currencyLocale: string;
49
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { fireCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await fireCalculator.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <SharedBibliography links={content.bibliography} />}