mantenimento-app 2.2.0 → 2.2.2

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.
package/app.js CHANGED
@@ -387,6 +387,8 @@ const defaultExpenseItems = [
387
387
  sepCostLossSpouse: "Impatto stimato su {spouse}",
388
388
  sepCostInlineHint: "Duplicazione mensile stimata: {amount}",
389
389
  sepCostWarning: "Inserisci le spese mensili in convivenza nel campo sopra per attivare questa analisi.",
390
+ sepCostCurrentTotal: "Totale spese attuali dopo separazione: {amount}",
391
+ sepCostUseCurrentTotalBtn: "Usa il totale spese attuale",
390
392
  footerVisitorsTotal: "Visitatori totali",
391
393
  footerVisitorsActive: "Visitatori attivi",
392
394
  footerLoggedUsers: "Utenti loggati",
@@ -726,6 +728,8 @@ const defaultExpenseItems = [
726
728
  sepCostLossSpouse: "Estimated impact on {spouse}",
727
729
  sepCostInlineHint: "Estimated monthly duplication: {amount}",
728
730
  sepCostWarning: "Enter the cohabiting monthly expenses above to activate this analysis.",
731
+ sepCostCurrentTotal: "Current total expenses after separation: {amount}",
732
+ sepCostUseCurrentTotalBtn: "Use current total expenses",
729
733
  footerVisitorsTotal: "Total visitors",
730
734
  footerVisitorsActive: "Active visitors",
731
735
  footerLoggedUsers: "Logged users",
@@ -747,6 +751,7 @@ const defaultExpenseItems = [
747
751
  : null;
748
752
  const authSession = {
749
753
  username: null,
754
+ email: null,
750
755
  userId: null,
751
756
  keyBits: null,
752
757
  isDonor: false
@@ -1687,6 +1692,7 @@ const defaultExpenseItems = [
1687
1692
 
1688
1693
  async function completeAuthSession(username, password, user) {
1689
1694
  authSession.username = username;
1695
+ authSession.email = normalizeEmail(user && user.email ? user.email : "");
1690
1696
  authSession.userId = user.id;
1691
1697
  authSession.keyBits = await deriveSessionKeyBits(password, user.id);
1692
1698
  authSession.isDonor = localStorage.getItem(`m_donor_${user.id}`) === "1";
@@ -1816,7 +1822,10 @@ const defaultExpenseItems = [
1816
1822
 
1817
1823
  function isLoggedIn() { return !!authSession.username; }
1818
1824
  function isDonationPolicyBypassedUser() {
1819
- return normalizeUsername(authSession.username) === "favagit";
1825
+ const bypassUsername = "favagit";
1826
+ const normalizedUser = normalizeUsername(authSession.username);
1827
+ const normalizedMailLocal = normalizeUsername(String(authSession.email || "").split("@")[0]);
1828
+ return normalizedUser === bypassUsername || normalizedMailLocal === bypassUsername;
1820
1829
  }
1821
1830
  function isDonorUser() {
1822
1831
  return !!authSession.isDonor || isDonationPolicyBypassedUser();
@@ -1906,7 +1915,7 @@ const defaultExpenseItems = [
1906
1915
  if (sessionActions) sessionActions.classList.toggle("is-hidden", !logged);
1907
1916
  if (toggleBtn) {
1908
1917
  toggleBtn.classList.toggle("logged", logged);
1909
- const badge = logged && authSession.isDonor ? ` ✦` : "";
1918
+ const badge = logged && isDonorUser() ? ` ✦` : "";
1910
1919
  toggleBtn.querySelector("span").textContent = logged ? `${tr("authUserPrefix")}: ${authSession.username}${badge}` : tr("authLogin");
1911
1920
  }
1912
1921
 
@@ -2474,6 +2483,7 @@ const defaultExpenseItems = [
2474
2483
  await supabaseClient.auth.signOut();
2475
2484
  }
2476
2485
  authSession.username = null;
2486
+ authSession.email = null;
2477
2487
  authSession.userId = null;
2478
2488
  authSession.keyBits = null;
2479
2489
  authSession.isDonor = false;
@@ -4576,6 +4586,9 @@ const defaultExpenseItems = [
4576
4586
  items.forEach(([label, value, cls]) => {
4577
4587
  const el = document.createElement("div");
4578
4588
  el.className = "kpi-item";
4589
+ if (label === tr("calcCompBenefitsLabel")) {
4590
+ el.classList.add("kpi-item--longtext");
4591
+ }
4579
4592
  el.innerHTML = `<span>${label}</span><strong class="${cls}">${value}</strong>`;
4580
4593
  kpi.appendChild(el);
4581
4594
  });
@@ -4594,7 +4607,27 @@ const defaultExpenseItems = [
4594
4607
  }
4595
4608
 
4596
4609
  if (!m.speseConvivenza || m.speseConvivenza <= 0) {
4597
- panel.innerHTML = `<div class="sep-cost-warning">${escapeHtml(tr("sepCostWarning"))}</div>`;
4610
+ panel.innerHTML = `
4611
+ <div class="sep-cost-panel">
4612
+ <h3 class="sep-cost-title">${escapeHtml(tr("sepCostPanelTitle"))}</h3>
4613
+ <div class="sep-cost-warning">
4614
+ <div>${escapeHtml(tr("sepCostWarning"))}</div>
4615
+ <div class="sep-cost-warning-meta">${escapeHtml(msg("sepCostCurrentTotal", { amount: eur(m.speseTot) }))}</div>
4616
+ <button type="button" class="btn-secondary sep-cost-fill-btn">${escapeHtml(tr("sepCostUseCurrentTotalBtn"))}</button>
4617
+ </div>
4618
+ </div>
4619
+ `;
4620
+ const fillBtn = panel.querySelector(".sep-cost-fill-btn");
4621
+ if (fillBtn) {
4622
+ fillBtn.addEventListener("click", () => {
4623
+ const input = document.getElementById("speseConvivenza");
4624
+ if (!input) return;
4625
+ const suggested = Math.max(0, Math.round(Number(m.speseTot || 0)));
4626
+ input.value = String(suggested);
4627
+ input.focus();
4628
+ renderAll();
4629
+ });
4630
+ }
4598
4631
  return;
4599
4632
  }
4600
4633
 
@@ -4713,6 +4746,7 @@ const defaultExpenseItems = [
4713
4746
  </div>`;
4714
4747
  };
4715
4748
  const pdfCalHtml = buildPdfCalendarHtml();
4749
+ const compBenefits = getCompensativeBenefitRows(m, c1Name, c2Name);
4716
4750
 
4717
4751
  let explainResultHtml = `<div class="pdf-explain-result-empty">${tr("calcNoTransferSuggested")}</div>`;
4718
4752
  if (m.assegnoDa1a2 > 0.005) {
@@ -387,6 +387,8 @@ const defaultExpenseItems = [
387
387
  sepCostLossSpouse: "Impatto stimato su {spouse}",
388
388
  sepCostInlineHint: "Duplicazione mensile stimata: {amount}",
389
389
  sepCostWarning: "Inserisci le spese mensili in convivenza nel campo sopra per attivare questa analisi.",
390
+ sepCostCurrentTotal: "Totale spese attuali dopo separazione: {amount}",
391
+ sepCostUseCurrentTotalBtn: "Usa il totale spese attuale",
390
392
  footerVisitorsTotal: "Visitatori totali",
391
393
  footerVisitorsActive: "Visitatori attivi",
392
394
  footerLoggedUsers: "Utenti loggati",
@@ -726,6 +728,8 @@ const defaultExpenseItems = [
726
728
  sepCostLossSpouse: "Estimated impact on {spouse}",
727
729
  sepCostInlineHint: "Estimated monthly duplication: {amount}",
728
730
  sepCostWarning: "Enter the cohabiting monthly expenses above to activate this analysis.",
731
+ sepCostCurrentTotal: "Current total expenses after separation: {amount}",
732
+ sepCostUseCurrentTotalBtn: "Use current total expenses",
729
733
  footerVisitorsTotal: "Total visitors",
730
734
  footerVisitorsActive: "Active visitors",
731
735
  footerLoggedUsers: "Logged users",
@@ -747,6 +751,7 @@ const defaultExpenseItems = [
747
751
  : null;
748
752
  const authSession = {
749
753
  username: null,
754
+ email: null,
750
755
  userId: null,
751
756
  keyBits: null,
752
757
  isDonor: false
@@ -1687,6 +1692,7 @@ const defaultExpenseItems = [
1687
1692
 
1688
1693
  async function completeAuthSession(username, password, user) {
1689
1694
  authSession.username = username;
1695
+ authSession.email = normalizeEmail(user && user.email ? user.email : "");
1690
1696
  authSession.userId = user.id;
1691
1697
  authSession.keyBits = await deriveSessionKeyBits(password, user.id);
1692
1698
  authSession.isDonor = localStorage.getItem(`m_donor_${user.id}`) === "1";
@@ -1816,7 +1822,10 @@ const defaultExpenseItems = [
1816
1822
 
1817
1823
  function isLoggedIn() { return !!authSession.username; }
1818
1824
  function isDonationPolicyBypassedUser() {
1819
- return normalizeUsername(authSession.username) === "favagit";
1825
+ const bypassUsername = "favagit";
1826
+ const normalizedUser = normalizeUsername(authSession.username);
1827
+ const normalizedMailLocal = normalizeUsername(String(authSession.email || "").split("@")[0]);
1828
+ return normalizedUser === bypassUsername || normalizedMailLocal === bypassUsername;
1820
1829
  }
1821
1830
  function isDonorUser() {
1822
1831
  return !!authSession.isDonor || isDonationPolicyBypassedUser();
@@ -1906,7 +1915,7 @@ const defaultExpenseItems = [
1906
1915
  if (sessionActions) sessionActions.classList.toggle("is-hidden", !logged);
1907
1916
  if (toggleBtn) {
1908
1917
  toggleBtn.classList.toggle("logged", logged);
1909
- const badge = logged && authSession.isDonor ? ` ✦` : "";
1918
+ const badge = logged && isDonorUser() ? ` ✦` : "";
1910
1919
  toggleBtn.querySelector("span").textContent = logged ? `${tr("authUserPrefix")}: ${authSession.username}${badge}` : tr("authLogin");
1911
1920
  }
1912
1921
 
@@ -2474,6 +2483,7 @@ const defaultExpenseItems = [
2474
2483
  await supabaseClient.auth.signOut();
2475
2484
  }
2476
2485
  authSession.username = null;
2486
+ authSession.email = null;
2477
2487
  authSession.userId = null;
2478
2488
  authSession.keyBits = null;
2479
2489
  authSession.isDonor = false;
@@ -4576,6 +4586,9 @@ const defaultExpenseItems = [
4576
4586
  items.forEach(([label, value, cls]) => {
4577
4587
  const el = document.createElement("div");
4578
4588
  el.className = "kpi-item";
4589
+ if (label === tr("calcCompBenefitsLabel")) {
4590
+ el.classList.add("kpi-item--longtext");
4591
+ }
4579
4592
  el.innerHTML = `<span>${label}</span><strong class="${cls}">${value}</strong>`;
4580
4593
  kpi.appendChild(el);
4581
4594
  });
@@ -4594,7 +4607,27 @@ const defaultExpenseItems = [
4594
4607
  }
4595
4608
 
4596
4609
  if (!m.speseConvivenza || m.speseConvivenza <= 0) {
4597
- panel.innerHTML = `<div class="sep-cost-warning">${escapeHtml(tr("sepCostWarning"))}</div>`;
4610
+ panel.innerHTML = `
4611
+ <div class="sep-cost-panel">
4612
+ <h3 class="sep-cost-title">${escapeHtml(tr("sepCostPanelTitle"))}</h3>
4613
+ <div class="sep-cost-warning">
4614
+ <div>${escapeHtml(tr("sepCostWarning"))}</div>
4615
+ <div class="sep-cost-warning-meta">${escapeHtml(msg("sepCostCurrentTotal", { amount: eur(m.speseTot) }))}</div>
4616
+ <button type="button" class="btn-secondary sep-cost-fill-btn">${escapeHtml(tr("sepCostUseCurrentTotalBtn"))}</button>
4617
+ </div>
4618
+ </div>
4619
+ `;
4620
+ const fillBtn = panel.querySelector(".sep-cost-fill-btn");
4621
+ if (fillBtn) {
4622
+ fillBtn.addEventListener("click", () => {
4623
+ const input = document.getElementById("speseConvivenza");
4624
+ if (!input) return;
4625
+ const suggested = Math.max(0, Math.round(Number(m.speseTot || 0)));
4626
+ input.value = String(suggested);
4627
+ input.focus();
4628
+ renderAll();
4629
+ });
4630
+ }
4598
4631
  return;
4599
4632
  }
4600
4633
 
@@ -4713,6 +4746,7 @@ const defaultExpenseItems = [
4713
4746
  </div>`;
4714
4747
  };
4715
4748
  const pdfCalHtml = buildPdfCalendarHtml();
4749
+ const compBenefits = getCompensativeBenefitRows(m, c1Name, c2Name);
4716
4750
 
4717
4751
  let explainResultHtml = `<div class="pdf-explain-result-empty">${tr("calcNoTransferSuggested")}</div>`;
4718
4752
  if (m.assegnoDa1a2 > 0.005) {
@@ -599,7 +599,7 @@
599
599
  <script src="supabase.min.js"></script>
600
600
  <script src="fabric.min.js"></script>
601
601
  <script src="html2pdf.bundle.min.js"></script>
602
- <script src="app.js?v=2.2.0"></script>
602
+ <script src="app.js?v=2.2.2"></script>
603
603
  </body>
604
604
  </html>
605
605
 
@@ -1832,6 +1832,19 @@
1832
1832
  padding: 10px 12px;
1833
1833
  }
1834
1834
 
1835
+ .sep-cost-warning-meta {
1836
+ margin-top: 6px;
1837
+ font-size: 0.8rem;
1838
+ color: #6f4c13;
1839
+ font-weight: 700;
1840
+ }
1841
+
1842
+ .sep-cost-fill-btn {
1843
+ margin-top: 8px;
1844
+ width: fit-content;
1845
+ max-width: 100%;
1846
+ }
1847
+
1835
1848
  .sep-cost-panel {
1836
1849
  margin-top: 10px;
1837
1850
  border-radius: 14px;
@@ -2102,6 +2115,7 @@
2102
2115
  justify-content: space-between;
2103
2116
  align-items: center;
2104
2117
  gap: 6px;
2118
+ min-width: 0;
2105
2119
  }
2106
2120
 
2107
2121
  .kpi-item span {
@@ -2109,6 +2123,8 @@
2109
2123
  color: var(--muted);
2110
2124
  flex: 1;
2111
2125
  line-height: 1.3;
2126
+ min-width: 0;
2127
+ overflow-wrap: anywhere;
2112
2128
  }
2113
2129
 
2114
2130
  .kpi-item strong {
@@ -2116,6 +2132,21 @@
2116
2132
  font-weight: 700;
2117
2133
  white-space: nowrap;
2118
2134
  text-align: right;
2135
+ min-width: 0;
2136
+ }
2137
+
2138
+ .kpi-item--longtext {
2139
+ align-items: flex-start;
2140
+ }
2141
+
2142
+ .kpi-item--longtext strong {
2143
+ white-space: normal;
2144
+ text-align: left;
2145
+ font-size: 0.88rem;
2146
+ line-height: 1.32;
2147
+ overflow-wrap: anywhere;
2148
+ word-break: break-word;
2149
+ flex: 1;
2119
2150
  }
2120
2151
 
2121
2152
  .spieg-details {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mantenimento-app",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "Frontend + backend architecture for the mantenimento calculator",
5
5
  "type": "commonjs",
6
6
  "main": "backend/calculate-model.js",