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 +37 -3
- package/frontend/public/app.js +37 -3
- package/frontend/public/index.html +1 -1
- package/frontend/public/styles.css +31 -0
- package/package.json +1 -1
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
|
-
|
|
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 &&
|
|
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 =
|
|
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) {
|
package/frontend/public/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
|
-
|
|
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 &&
|
|
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 =
|
|
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) {
|
|
@@ -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 {
|