Walrus blob · mainnet
import { c as le, x as Me, b as Le, d as $e, i as Fe, r as n, j as e, X as Te, a1 as ze, a as Ee, a2 as Be, D as Ye, y as De, k as Oe, L as We, z as _e, M as Je, a0 as Ne, a3 as ve } from "./index-CeMnqBop.js";
import { C as Ve } from "./circle-alert-Y0Ebw64U.js";
import { S as Ge } from "./save-DXLy-TqM.js";
import { R as Ke } from "./refresh-cw-B7QjnYq-.js";
import { T as He } from "./trash-2-XZz4bnYZ.js";
import { N as P } from "./NumberField-BZqVoR-9.js";
import { I as Ue } from "./info-DGiFNqw7.js";
import { T as qe } from "./table-B-3QXXyR.js";
import { C as Se } from "./chevron-right-DgqGwI-L.js";
/**
* @license lucide-react v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/
const Xe = le("Bookmark", [["path", { d: "m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z", key: "1fy3hk" }]]);
/**
* @license lucide-react v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/
const Qe = le("CreditCard", [["rect", { width: "20", height: "14", x: "2", y: "5", rx: "2", key: "ynyp8z" }], ["line", { x1: "2", x2: "22", y1: "10", y2: "10", key: "1b3vmo" }]]);
/**
* @license lucide-react v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/
const Ze = le("Rocket", [["path", { d: "M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z", key: "m3kijz" }], ["path", { d: "m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z", key: "1fmvmk" }], ["path", { d: "M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0", key: "1f8sc4" }], ["path", { d: "M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5", key: "qeys4" }]]);
/**
* @license lucide-react v0.469.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*/
const et = le("Target", [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }], ["circle", { cx: "12", cy: "12", r: "6", key: "1vlfrh" }], ["circle", { cx: "12", cy: "12", r: "2", key: "1c9p78" }]]);
function Z(t) {
const { principal: r, annualRate: a, years: i, bonusRatio: s, startBalance: c = r, startMonthIndex: N = 1, customMonthlyPayment: C, customBonusPayment: p } = t, g = i * 12, d = a / 100 / 12, l = a / 100 / 2, j = r * (s / 100), v = r - j;
let o = 0;
v > 0 && g > 0 && (o = d > 0 ? Math.floor(v * d * Math.pow(1 + d, g) / (Math.pow(1 + d, g) - 1)) : Math.floor(v / g));
let L = 0;
const w = i * 2;
j > 0 && w > 0 && (L = l > 0 ? Math.floor(j * l * Math.pow(1 + l, w) / (Math.pow(1 + l, w) - 1)) : Math.floor(j / w));
const h = C !== void 0 ? C : o, R = p !== void 0 ? p : L, x = [];
let m = c * (1 - s / 100), y = c * (s / 100), k = 0, A = 0, M = N;
const J = g * 2;
for (; m + y > 0 && A < J; ) {
const q = Math.floor((M - 1) / 12), X = (M - 1) % 12 + 1, V = X === 6 || X === 12;
let W = 0, Y = 0;
if (m > 0) {
const $ = Math.floor(m * d), Q = h - $, T = Math.min(Q, m);
m -= T, W += $, Y += T;
}
if (V && y > 0) {
const $ = Math.floor(y * l), Q = R - $, T = Math.min(Q, y);
y -= T, W += $, Y += T;
}
m < 0.01 && (m = 0), y < 0.01 && (y = 0);
const ee = m + y, F = Y + W;
(F > 0 || ee > 0) && (x.push({ monthIndex: M, year: q + 1, month: X, payment: F, principal: Y, interest: W, balance: ee, isBonusMonth: V }), k += W, A++), M++;
}
const U = c + k;
return { monthlyPayment: h, bonusPayment: R, totalPayment: U, totalInterest: k, interestRatio: U > 0 ? k / U * 100 : 0, yearlyPayment: h * 12 + R * 2, schedule: x, totalMonths: A };
}
function tt(t, r, a, i) {
const s = Z(t);
if (r >= s.schedule.length || s.schedule.length === 0) return { base: s, new: s, prepayEventRowIndex: -1 };
const c = s.schedule.findIndex((h) => h.monthIndex === r);
if (c === -1) return { base: s, new: s, prepayEventRowIndex: -1 };
const N = c > 0 ? Math.floor(s.schedule[c - 1].balance) : t.principal, C = Math.min(a, N), p = N - C, g = s.schedule.slice(0, c), d = g.reduce((h, R) => h + R.interest, 0);
let l;
if (p <= 0) l = { monthlyPayment: 0, bonusPayment: 0, totalPayment: 0, totalInterest: 0, interestRatio: 0, yearlyPayment: 0, schedule: [], totalMonths: 0 };
else if (i === "shorten") l = Z({ ...t, startBalance: p, startMonthIndex: r, customMonthlyPayment: s.monthlyPayment, customBonusPayment: s.bonusPayment });
else {
const R = (s.totalMonths - c) / 12;
l = Z({ ...t, principal: p, years: R, startBalance: p, startMonthIndex: r });
}
const j = { monthIndex: r, year: Math.floor((r - 1) / 12) + 1, month: (r - 1) % 12 + 1, payment: C, principal: C, interest: 0, balance: p, isBonusMonth: false }, v = [...g, j, ...l.schedule], o = d + l.totalInterest, L = t.principal + o, w = { monthlyPayment: l.monthlyPayment || s.monthlyPayment, bonusPayment: l.bonusPayment || s.bonusPayment, totalPayment: L, totalInterest: o, interestRatio: o / L * 100, yearlyPayment: l.yearlyPayment || s.yearlyPayment, schedule: v, totalMonths: v.length, savedInterest: Math.max(0, s.totalInterest - o), shortenedMonths: Math.max(0, s.totalMonths - v.length + 1) };
return { base: s, new: w, prepayEventRowIndex: c };
}
function at(t, r, a, i, s) {
const c = Z(t), N = c.schedule.findIndex((w) => w.monthIndex === r);
if (N === -1 || N >= c.schedule.length) return { base: c, new: c, savedInterest: 0 };
const C = N > 0 ? c.schedule[N - 1].balance : t.principal, p = c.schedule.slice(0, N), g = p.reduce((w, h) => w + h.interest, 0), d = C + s, l = Z({ principal: d, annualRate: a, years: i, bonusRatio: 0, startMonthIndex: r }), j = [...p, ...l.schedule], v = g + l.totalInterest, o = t.principal - C + l.totalPayment, L = { monthlyPayment: l.monthlyPayment, bonusPayment: 0, totalPayment: o, totalInterest: v + s, interestRatio: (v + s) / o * 100, yearlyPayment: l.yearlyPayment, schedule: j, totalMonths: j.length };
return { base: c, new: L, savedInterest: c.totalPayment - o };
}
const we = "loan_scenarios", Ce = "loan_scenarios_v1", st = 2160 * 60 * 60 * 1e3, rt = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 9);
function nt() {
try {
const t = localStorage.getItem(Me(Ce));
if (!t) return [];
const r = JSON.parse(t);
return Array.isArray(r) ? he(r) : [];
} catch {
return [];
}
}
function lt(t) {
try {
localStorage.setItem(Me(Ce), JSON.stringify(t));
} catch {
}
}
function me(t) {
if (typeof t.updatedAtMs == "number" && Number.isFinite(t.updatedAtMs)) return t;
const r = t.createdAt ? Date.parse(t.createdAt) : 0;
return { ...t, updatedAtMs: Number.isFinite(r) ? r : 0 };
}
function he(t, r = Date.now()) {
return t.filter((a) => a && typeof a.id == "string").map(me).filter((a) => !a.deleted || r - (a.deletedAtMs ?? r) < st);
}
function ot(t, r) {
const a = /* @__PURE__ */ new Map();
for (const i of t) a.set(i.id, me(i));
for (const i of r) {
const s = me(i), c = a.get(s.id);
(!c || (s.updatedAtMs ?? 0) > (c.updatedAtMs ?? 0)) && a.set(s.id, s);
}
return he([...a.values()]);
}
function ne(t) {
return JSON.stringify([...t].sort((r, a) => r.id < a.id ? -1 : r.id > a.id ? 1 : 0));
}
function it() {
const { currentUserAddress: t } = Le(), { syncToWalrus: r } = $e(), { restoreNamespace: a } = Fe(), [i, s] = n.useState(() => nt()), [c, N] = n.useState("idle"), [C, p] = n.useState(null), g = n.useRef(i);
g.current = i, n.useEffect(() => {
lt(i);
}, [i]);
const d = n.useRef({ count: 0, timer: null }), l = n.useCallback(async (x) => {
if (t) {
N("syncing");
try {
const m = { version: 1, scenarios: x, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
await r({ payload: m, appNamespace: we }), N("synced"), p(Date.now()), d.current.count = 0, d.current.timer && (window.clearTimeout(d.current.timer), d.current.timer = null);
} catch (m) {
if (N("error"), console.warn("[loan] sync failed", m), d.current.timer && window.clearTimeout(d.current.timer), d.current.count < 3) {
const y = 3e4 * 2 ** d.current.count;
d.current.count += 1, d.current.timer = window.setTimeout(() => {
j.current(g.current);
}, y);
}
}
}
}, [t, r]), j = n.useRef(l);
j.current = l;
const v = n.useCallback(async () => {
if (t) try {
const x = await a(we);
if (!x || !Array.isArray(x.scenarios)) {
g.current.filter((A) => !A.deleted).length > 0 && l(g.current);
return;
}
const m = g.current, y = ot(m, x.scenarios), k = he(x.scenarios);
ne(y) !== ne(m) && s(y), ne(y) !== ne(k) && l(y);
} catch (x) {
console.warn("[loan] restore failed", x);
}
}, [t, a, l]), o = n.useRef(v);
o.current = v, n.useEffect(() => {
if (!t) return;
o.current();
const x = () => {
document.hidden || o.current();
};
return window.addEventListener("focus", x), document.addEventListener("visibilitychange", x), () => {
window.removeEventListener("focus", x), document.removeEventListener("visibilitychange", x);
};
}, [t]);
const L = n.useCallback((x, m) => {
const y = Date.now(), k = { id: rt(), name: x.trim() || "\u7121\u984C\u306E\u30B7\u30CA\u30EA\u30AA", createdAt: (/* @__PURE__ */ new Date()).toISOString(), updatedAtMs: y, params: m }, A = [k, ...g.current];
return s(A), l(A), k.id;
}, [l]), w = n.useCallback((x, m, y) => {
const k = Date.now(), A = g.current.map((M) => M.id === x ? { ...M, params: m, name: (y == null ? void 0 : y.trim()) || M.name, updatedAtMs: k } : M);
s(A), l(A);
}, [l]), h = n.useCallback((x) => {
const m = Date.now(), y = g.current.map((k) => k.id === x ? { ...k, deleted: true, deletedAtMs: m, updatedAtMs: m } : k);
s(y), l(y);
}, [l]);
return { scenarios: i.filter((x) => !x.deleted).sort((x, m) => m.updatedAtMs - x.updatedAtMs), saveScenario: L, updateScenario: w, removeScenario: h, isLoggedIn: !!t, syncPhase: c, lastSyncedAt: C };
}
const ct = (t) => new Intl.NumberFormat("ja-JP").format(Math.round(t));
function dt({ isOpen: t, onClose: r, scenarios: a, defaultName: i, onSave: s, onUpdate: c, onDelete: N, onLoad: C, isLoggedIn: p, syncPhase: g, lastSyncedAt: d }) {
const [l, j] = n.useState("");
if (!t) return null;
const v = () => {
s(l.trim() || i), j("");
};
return e.jsx("div", { className: "fixed inset-0 z-50 flex items-end sm:items-center justify-center bg-black/40 backdrop-blur-sm", onClick: r, children: e.jsxs("div", { className: "bg-white dark:bg-gray-900 w-full sm:max-w-lg sm:rounded-2xl rounded-t-2xl shadow-2xl border border-gray-200 dark:border-gray-800 max-h-[88vh] flex flex-col", onClick: (o) => o.stopPropagation(), children: [e.jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-gray-100 dark:border-gray-800", children: [e.jsx("h2", { className: "text-lg font-bold text-gray-900 dark:text-gray-100", children: "\u6761\u4EF6\u306E\u4FDD\u5B58\u30FB\u547C\u3073\u51FA\u3057" }), e.jsx("button", { onClick: r, className: "p-1.5 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors", children: e.jsx(Te, { size: 20 }) })] }), e.jsx("div", { className: "px-5 pt-3", children: p ? e.jsx("div", { className: "flex items-center gap-1.5 text-[12px] font-medium", children: g === "syncing" ? e.jsxs("span", { className: "flex items-center gap-1 text-blue-600 dark:text-blue-300", children: [e.jsx(Ee, { size: 13, className: "animate-spin" }), " \u540C\u671F\u4E2D\u2026"] }) : g === "error" ? e.jsxs("span", { className: "flex items-center gap-1 text-red-500", children: [e.jsx(Ve, { size: 13 }), " \u540C\u671F\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF08\u6B21\u56DE\u518D\u8A66\u884C\uFF09"] }) : e.jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", title: d ? `\u6700\u7D42\u540C\u671F: ${new Date(d).toLocaleTimeString("ja-JP")}` : "", children: [e.jsx(Be, { size: 13 }), " \u7AEF\u672B\u9593\u3067\u540C\u671F\u4E2D"] }) }) : e.jsxs("div", { className: "flex items-start gap-2 text-[12px] text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded-lg px-3 py-2", children: [e.jsx(ze, { size: 15, className: "mt-0.5 shrink-0" }), e.jsxs("span", { children: ["\u672A\u30ED\u30B0\u30A4\u30F3\uFF1A\u3053\u306E\u7AEF\u672B\u306B\u306E\u307F\u4FDD\u5B58\u3055\u308C\u307E\u3059\u3002", e.jsx("br", { className: "hidden sm:block" }), "\u4ED6\u306E\u7AEF\u672B\u3068\u540C\u671F\u3059\u308B\u306B\u306F\u3001\u30DB\u30FC\u30E0\u304B\u3089\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u304F\u3060\u3055\u3044\u3002"] })] }) }), e.jsxs("div", { className: "px-5 py-3", children: [e.jsxs("div", { className: "flex items-center gap-2", children: [e.jsx("input", { type: "text", value: l, onChange: (o) => j(o.target.value), onKeyDown: (o) => o.key === "Enter" && v(), placeholder: i, className: "flex-1 text-[15px] bg-gray-50 dark:bg-gray-800 rounded-lg px-3 py-2.5 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 outline-none focus:ring-2 focus:ring-blue-500/40" }), e.jsxs("button", { onClick: v, className: "flex items-center gap-1.5 px-4 py-2.5 bg-blue-500 text-white rounded-lg font-semibold text-[15px] active:bg-blue-600 transition-colors shrink-0", children: [e.jsx(Ge, { size: 16 }), " \u4FDD\u5B58"] })] }), e.jsx("p", { className: "text-[11px] text-gray-400 mt-1.5 px-0.5", children: "\u73FE\u5728\u306E\u5165\u529B\u6761\u4EF6\uFF08\u57FA\u672C\u30FB\u7E70\u4E0A\u30FB\u501F\u63DB\u30FB\u53CE\u652F\uFF09\u3092\u4FDD\u5B58\u3057\u307E\u3059\u3002" })] }), e.jsx("div", { className: "flex-1 overflow-y-auto px-5 pb-2 min-h-[80px]", children: a.length === 0 ? e.jsx("p", { className: "text-center text-sm text-gray-400 dark:text-gray-500 py-8", children: "\u4FDD\u5B58\u3055\u308C\u305F\u6761\u4EF6\u306F\u307E\u3060\u3042\u308A\u307E\u305B\u3093" }) : e.jsx("div", { className: "space-y-2", children: a.map((o) => e.jsx("div", { className: "border border-gray-200 dark:border-gray-700 rounded-xl p-3 bg-white dark:bg-gray-800/40", children: e.jsxs("div", { className: "flex items-start justify-between gap-2", children: [e.jsxs("div", { className: "min-w-0 flex-1", children: [e.jsx("div", { className: "font-semibold text-[15px] text-gray-900 dark:text-gray-100 truncate", children: o.name }), e.jsxs("div", { className: "text-[12px] text-gray-500 dark:text-gray-400 mt-0.5", children: ["\u501F\u5165 \xA5", ct(o.params.loanAmount), " / ", o.params.interestRate, "% / ", o.params.loanTermYears, "\u5E74"] }), e.jsx("div", { className: "text-[10px] text-gray-400 mt-0.5", children: new Date(o.updatedAtMs).toLocaleString("ja-JP", { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }) })] }), e.jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [e.jsxs("button", { onClick: () => {
C(o), r();
}, title: "\u3053\u306E\u6761\u4EF6\u3092\u8AAD\u307F\u8FBC\u3080", className: "flex items-center gap-1 px-2.5 py-1.5 rounded-lg bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-300 text-[13px] font-medium active:scale-95 transition-transform", children: [e.jsx(Ye, { size: 14 }), " \u547C\u51FA"] }), e.jsx("button", { onClick: () => c(o.id, o.name), title: "\u73FE\u5728\u306E\u5165\u529B\u3067\u4E0A\u66F8\u304D\u4FDD\u5B58", className: "p-1.5 rounded-lg text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700", children: e.jsx(Ke, { size: 15 }) }), e.jsx("button", { onClick: () => N(o.id), title: "\u524A\u9664", className: "p-1.5 rounded-lg text-gray-300 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20", children: e.jsx(He, { size: 15 }) })] })] }) }, o.id)) }) }), e.jsx("div", { className: "px-5 py-3 border-t border-gray-100 dark:border-gray-800", children: e.jsx("p", { className: "text-[10.5px] leading-relaxed text-gray-400 dark:text-gray-500", children: "\u203B \u8A08\u7B97\u7D50\u679C\u30FB\u4FDD\u5B58\u5185\u5BB9\u306F\u6982\u7B97\u3067\u3042\u308A\u3001\u6B63\u78BA\u6027\u30FB\u6700\u65B0\u6027\u3092\u4FDD\u8A3C\u3059\u308B\u3082\u306E\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u91D1\u878D\u30FB\u7A0E\u52D9\u30FB\u6CD5\u5F8B\u4E0A\u306E\u52A9\u8A00\u3067\u306F\u306A\u304F\u3001\u5B9F\u969B\u306E\u501F\u5165\u6761\u4EF6\u306F\u91D1\u878D\u6A5F\u95A2\u30FB\u5C02\u9580\u5BB6\u306B\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002\u4FDD\u5B58\u30C7\u30FC\u30BF\u306F\u7AEF\u672B\u5074\u3067\u6697\u53F7\u5316\u306E\u3046\u3048\u4FDD\u5B58\u3055\u308C\u3001\u305D\u306E\u7BA1\u7406\u306F\u5229\u7528\u8005\u3054\u81EA\u8EAB\u306E\u8CAC\u4EFB\u3068\u306A\u308A\u307E\u3059\u3002\u672C\u30C4\u30FC\u30EB\u306E\u5229\u7528\u306B\u3088\u308A\u751F\u3058\u305F\u3044\u304B\u306A\u308B\u640D\u5BB3\u306B\u3064\u3044\u3066\u3082\u63D0\u4F9B\u8005\u306F\u8CAC\u4EFB\u3092\u8CA0\u3044\u307E\u305B\u3093\uFF08\u8A73\u7D30\u306F\u5229\u7528\u898F\u7D04\u3092\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\uFF09\u3002" }) })] }) });
}
const B = ({ title: t, children: r, className: a = "" }) => e.jsxs("div", { className: `mb-6 ${a}`, children: [t && e.jsx("h2", { className: "px-4 mb-2 text-xs font-semibold text-gray-500 uppercase tracking-wider", children: t }), e.jsx("div", { className: "bg-white dark:bg-gray-900 border-y sm:border-x sm:rounded-xl border-gray-200 dark:border-gray-800 overflow-hidden", children: e.jsx("div", { className: "divide-y divide-gray-100 dark:divide-gray-800 ml-4", children: r }) })] }), S = ({ label: t, value: r, input: a, hasArrow: i = true, valueColor: s = "text-gray-500 dark:text-gray-400", onClick: c }) => e.jsxs("div", { className: `flex justify-between items-center py-3 pr-4 bg-white dark:bg-gray-900 min-h-[44px] ${c ? "cursor-pointer active:bg-gray-50 dark:active:bg-gray-800 transition-colors" : ""}`, onClick: c, children: [e.jsx("label", { className: "text-[17px] text-gray-900 dark:text-gray-100 whitespace-nowrap mr-4", children: t }), e.jsxs("div", { className: "flex items-center flex-1 justify-end", children: [a || e.jsx("span", { className: `text-[17px] ${s} truncate`, children: r }), i && !a && e.jsx(Se, { size: 20, className: "ml-2 text-gray-300 dark:text-gray-600 flex-shrink-0" })] })] }), xe = ({ options: t, selected: r, onChange: a }) => e.jsx("div", { className: "flex p-1 bg-gray-200 dark:bg-gray-800 rounded-lg mx-4 mb-4", children: t.map((i) => e.jsxs("button", { onClick: () => a(i.id), className: `flex-1 py-1.5 text-sm font-medium rounded-md transition-all flex items-center justify-center gap-1.5 ${r === i.id ? "bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm" : "text-gray-500 hover:text-gray-700 dark:text-gray-400"}`, children: [i.icon && e.jsx(i.icon, { size: 16 }), i.label] }, i.id)) }), b = (t) => new Intl.NumberFormat("ja-JP").format(Math.round(t));
function jt() {
const { theme: t, toggleTheme: r } = De(), [a, i] = n.useState("conditions"), [s, c] = n.useState("summary"), [N, C] = n.useState("prepay"), [p, g] = n.useState(3e7), [d, l] = n.useState(1.45), [j, v] = n.useState(35), [o, L] = n.useState(0), w = n.useMemo(() => ({ principal: p, annualRate: d, years: j, bonusRatio: o }), [p, d, j, o]), h = n.useMemo(() => Z(w), [w]), [R, x] = n.useState(10), [m, y] = n.useState(5e6), [k, A] = n.useState("shorten"), M = n.useMemo(() => tt(w, R * 12, m, k), [w, R, m, k]), [J, U] = n.useState(10), [q, X] = n.useState(0.8), [V, W] = n.useState(25), [Y, ee] = n.useState(5e5), F = n.useMemo(() => at(w, J * 12, q, V, Y), [w, J, q, V, Y]), [$, Q] = n.useState(0), [T, ue] = n.useState(0), [te, pe] = n.useState(0), [D, oe] = n.useState("rate"), [ae, se] = n.useState(5), [re, ge] = n.useState(0), _ = it(), [Pe, ye] = n.useState(false), be = () => ({ loanAmount: p, interestRate: d, loanTermYears: j, bonusRatio: o, prepayYear: R, prepayAmount: m, prepayType: k, refiYear: J, refiNewRate: q, refiNewYears: V, refiFee: Y, rent: $, mngFee: T, resFee: te, pmFeeMode: D, pmFeeInput: ae, taxYearly: re }), Ae = (f) => {
const u = f.params;
g(u.loanAmount), l(u.interestRate), v(u.loanTermYears), L(u.bonusRatio), x(u.prepayYear), y(u.prepayAmount), A(u.prepayType), U(u.refiYear), X(u.refiNewRate), W(u.refiNewYears), ee(u.refiFee), Q(u.rent), ue(u.mngFee), pe(u.resFee), oe(u.pmFeeMode), se(u.pmFeeInput), ge(u.taxYearly);
}, Re = `\u501F\u5165${b(p)}\u5186\u30FB${d}%\u30FB${j}\u5E74`, z = n.useMemo(() => {
const f = h.monthlyPayment + h.bonusPayment * 2 / 12, u = Math.floor(D === "rate" ? $ * (ae / 100) * 1.1 : ae), G = Math.floor(re / 12), K = f + T + te + u + G, O = Math.floor($ - K), I = O * 12;
return { monthlyLoanPayment: Math.floor(f), pmFeeActual: u, taxMonthly: G, monthlyExpense: Math.floor(K), monthlyCf: O, annualCf: I };
}, [h, $, T, te, D, ae, re]);
n.useEffect(() => {
t === "dark" ? document.documentElement.classList.add("dark") : document.documentElement.classList.remove("dark");
}, [t]);
const fe = e.jsxs("div", { className: "animate-in fade-in duration-300", children: [e.jsx("div", { className: "px-4 py-4 md:py-2", children: e.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "\u57FA\u672C\u9805\u76EE\u3092\u8A2D\u5B9A\u3059\u308B\u3060\u3051\u3067\u8A66\u7B97\u30FB\u6BD4\u8F03\u304C\u3067\u304D\u307E\u3059\u3002" }) }), e.jsxs(B, { title: "\u57FA\u672C\u6761\u4EF6", children: [e.jsx(S, { label: "\u501F\u5165\u91D1\u984D\u5408\u8A08", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: p, onChange: g, group: true, placeholder: "30,000,000", ariaLabel: "\u501F\u5165\u91D1\u984D\u5408\u8A08", className: "w-36 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "\u5186" })] }), hasArrow: false }), e.jsx(S, { label: "\u91D1\u5229 (\u56FA\u5B9A)", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: d, onChange: l, decimals: true, placeholder: "1.45", ariaLabel: "\u91D1\u5229", className: "w-20 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "%" })] }), hasArrow: false }), e.jsx(S, { label: "\u671F\u9593", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: j, onChange: v, min: 1, max: 50, placeholder: "35", ariaLabel: "\u671F\u9593\uFF08\u5E74\uFF09", className: "w-16 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsxs("span", { className: "ml-1 text-[17px] text-gray-400 whitespace-nowrap", children: ["\u5E74 (", j * 12, "\u56DE)"] })] }), hasArrow: false })] }), e.jsx(B, { title: "\u8A73\u7D30\u8A2D\u5B9A", children: e.jsx(S, { label: "\u30DC\u30FC\u30CA\u30B9\u8FD4\u6E08\u5272\u5408", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: o, onChange: L, min: 0, max: 50, placeholder: "0", ariaLabel: "\u30DC\u30FC\u30CA\u30B9\u8FD4\u6E08\u5272\u5408", className: "w-16 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "%" })] }), hasArrow: false }) }), e.jsx("div", { className: "px-4 mt-4 mb-2", children: e.jsx("p", { className: "text-[11px] leading-relaxed text-gray-400 dark:text-gray-500", children: "\u203B \u8A08\u7B97\u7D50\u679C\u306F\u6982\u7B97\uFF08\u53C2\u8003\u5024\uFF09\u3067\u3059\u3002\u91D1\u878D\u30FB\u7A0E\u52D9\u30FB\u6CD5\u5F8B\u4E0A\u306E\u52A9\u8A00\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u5B9F\u969B\u306E\u501F\u5165\u6761\u4EF6\u30FB\u91D1\u5229\u30FB\u7A0E\u984D\u7B49\u306F\u91D1\u878D\u6A5F\u95A2\u3084\u5C02\u9580\u5BB6\u306B\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002\u672C\u30C4\u30FC\u30EB\u306E\u5229\u7528\u306B\u3088\u308A\u751F\u3058\u305F\u640D\u5BB3\u306B\u3064\u3044\u3066\u63D0\u4F9B\u8005\u306F\u8CAC\u4EFB\u3092\u8CA0\u3044\u307E\u305B\u3093\u3002" }) }), e.jsx("div", { className: "px-4 mt-4 mb-6 md:hidden", children: e.jsx("button", { onClick: () => i("results"), className: "w-full py-3.5 bg-blue-500 text-white rounded-xl font-semibold text-[17px] active:bg-blue-600 transition-colors shadow-sm", children: "\u8A66\u7B97\u7D50\u679C\u3092\u898B\u308B" }) })] }), ie = (f, u, G) => {
const K = f.schedule, O = u == null ? void 0 : u.schedule, I = Math.max(f.totalMonths, (u == null ? void 0 : u.totalMonths) || 0);
return I === 0 ? null : e.jsxs("div", { className: "p-4", children: [e.jsxs("div", { className: "h-64 w-full relative", children: [e.jsxs("svg", { viewBox: "0 0 100 100", preserveAspectRatio: "none", className: "w-full h-full overflow-visible", children: [e.jsxs("defs", { children: [e.jsxs("linearGradient", { id: "baseFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [e.jsx("stop", { offset: "0%", stopColor: "#9ca3af", stopOpacity: "0.4" }), e.jsx("stop", { offset: "100%", stopColor: "#9ca3af", stopOpacity: "0.0" })] }), e.jsxs("linearGradient", { id: "newFill", x1: "0", y1: "0", x2: "0", y2: "1", children: [e.jsx("stop", { offset: "0%", stopColor: "#3b82f6", stopOpacity: "0.5" }), e.jsx("stop", { offset: "100%", stopColor: "#3b82f6", stopOpacity: "0.1" })] })] }), [0, 25, 50, 75, 100].map((E) => e.jsx("line", { x1: "0", y1: E, x2: "100", y2: E, stroke: "currentColor", strokeWidth: "0.5", className: "text-gray-200 dark:text-gray-800" }, `grid-${E}`)), K.length > 0 && e.jsx("polygon", { fill: "url(#baseFill)", points: `0,100 ${K.map((E, H) => {
const ce = H / I * 100, de = 100 - E.balance / p * 100;
return `${ce},${de}`;
}).join(" ")} ${(K.length - 1) / I * 100},100` }), e.jsx("polyline", { fill: "none", stroke: "#9ca3af", strokeWidth: "1.5", strokeDasharray: u ? "4,4" : "0", points: K.map((E, H) => `${H / I * 100},${100 - Math.max(0, E.balance / p * 100)}`).join(" ") }), O && O.length > 0 && e.jsx("polygon", { fill: "url(#newFill)", points: `0,100 ${O.map((E, H) => {
const ce = H / I * 100, de = 100 - E.balance / p * 100;
return `${ce},${de}`;
}).join(" ")} ${(O.length - 1) / I * 100},100` }), O && e.jsx("polyline", { fill: "none", stroke: "#3b82f6", strokeWidth: "2.5", points: O.map((E, H) => `${H / I * 100},${100 - Math.max(0, E.balance / p * 100)}`).join(" ") }), G !== void 0 && G > 0 && e.jsx("line", { x1: G / I * 100, y1: "0", x2: G / I * 100, y2: "100", stroke: "#f59e0b", strokeWidth: "1.5", strokeDasharray: "3,3" })] }), e.jsxs("div", { className: "flex justify-between text-[10px] text-gray-400 mt-2 border-t border-gray-200 dark:border-gray-800 pt-1", children: [e.jsx("span", { children: "\u958B\u59CB" }), e.jsxs("span", { children: [Math.floor(I / 2 / 12), "\u5E74"] }), e.jsxs("span", { children: [Math.ceil(I / 12), "\u5E74"] })] })] }), e.jsxs("div", { className: "flex justify-center space-x-6 mt-6", children: [e.jsxs("div", { className: "flex items-center", children: [e.jsx("div", { className: "w-4 h-1 bg-gray-400 mr-2 rounded" }), e.jsx("span", { className: "text-xs text-gray-500", children: "\u57FA\u672C\u30D7\u30E9\u30F3" })] }), u && e.jsxs("div", { className: "flex items-center", children: [e.jsx("div", { className: "w-4 h-1 bg-blue-500 mr-2 rounded" }), e.jsx("span", { className: "text-xs font-medium text-gray-900 dark:text-gray-100", children: "\u65B0\u30D7\u30E9\u30F3\u60F3\u5B9A" })] })] })] });
}, Ie = e.jsxs("div", { className: "animate-in fade-in", children: [e.jsxs(B, { title: "\u53CE\u652F\u30B7\u30DF\u30E5\u30EC\u30FC\u30B7\u30E7\u30F3\uFF08\u4E0D\u52D5\u7523\u6295\u8CC7\uFF09", children: [e.jsx(S, { label: "\u8CC3\u6599\u53CE\u5165\uFF08\u6708\u984D\uFF09", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: $, onChange: Q, group: true, placeholder: "100,000", ariaLabel: "\u8CC3\u6599\u53CE\u5165\uFF08\u6708\u984D\uFF09", className: "w-28 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "\u5186" })] }), hasArrow: false }), e.jsx(S, { label: "\u7BA1\u7406\u8CBB\uFF08\u6708\u984D\uFF09", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: T, onChange: ue, group: true, placeholder: "10,000", ariaLabel: "\u7BA1\u7406\u8CBB\uFF08\u6708\u984D\uFF09", className: "w-28 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "\u5186" })] }), hasArrow: false }), e.jsx(S, { label: "\u4FEE\u7E55\u7A4D\u7ACB\u91D1\uFF08\u6708\u984D\uFF09", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: te, onChange: pe, group: true, placeholder: "5,000", ariaLabel: "\u4FEE\u7E55\u7A4D\u7ACB\u91D1\uFF08\u6708\u984D\uFF09", className: "w-28 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "\u5186" })] }), hasArrow: false }), e.jsxs("div", { className: "py-3 pr-4 bg-white dark:bg-gray-900", children: [e.jsx("div", { className: "flex justify-between items-center mb-2", children: e.jsx("label", { className: "text-[17px] text-gray-900 dark:text-gray-100", children: "\u8CC3\u8CB8\u7BA1\u7406Fee\uFF08\u6708\u984D\uFF09" }) }), e.jsxs("div", { className: "flex items-center gap-3 justify-end", children: [e.jsxs("div", { className: "flex p-0.5 bg-gray-200 dark:bg-gray-800 rounded-lg", children: [e.jsx("button", { onClick: () => {
oe("rate"), se(5);
}, className: `px-3 py-1 text-xs font-medium rounded-md transition-all ${D === "rate" ? "bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm" : "text-gray-500"}`, children: "\u7387 (%)" }), e.jsx("button", { onClick: () => {
oe("amount"), se(0);
}, className: `px-3 py-1 text-xs font-medium rounded-md transition-all ${D === "amount" ? "bg-white dark:bg-gray-600 text-gray-900 dark:text-white shadow-sm" : "text-gray-500"}`, children: "\u5B9F\u984D (\u5186)" })] }), e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: ae, onChange: se, group: D === "amount", decimals: D === "rate", placeholder: D === "rate" ? "5" : "5,000", ariaLabel: "\u8CC3\u8CB8\u7BA1\u7406Fee\uFF08\u6708\u984D\uFF09", className: "w-20 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: D === "rate" ? "%" : "\u5186" })] })] }), D === "rate" && $ > 0 && e.jsxs("p", { className: "text-[11px] text-gray-400 dark:text-gray-500 text-right mt-1 pr-0", children: ["\u5B9F\u984D: \xA5", b(z.pmFeeActual), "/\u6708\uFF08\u6D88\u8CBB\u7A0E\u8FBC\uFF09"] })] }), e.jsx(S, { label: "\u56FA\u90FD\u7A0E\uFF08\u5E74\u984D\uFF09", input: e.jsxs("div", { className: "flex items-center", children: [e.jsx(P, { value: re, onChange: ge, group: true, placeholder: "60,000", ariaLabel: "\u56FA\u90FD\u7A0E\uFF08\u5E74\u984D\uFF09", className: "w-28 text-right bg-transparent border-none p-0 focus:ring-0 text-[17px] text-blue-500 font-medium outline-none placeholder-gray-300 dark:placeholder-gray-600" }), e.jsx("span", { className: "ml-1 text-[17px] text-gray-400", children: "\u5186" })] }), hasArrow: false })] }), e.jsxs(B, { title: "\u30AD\u30E3\u30C3\u30B7\u30E5\u30D5\u30ED\u30FC\u8A66\u7B97\u7D50\u679C", children: [e.jsxs("div", { className: "px-4 py-5 border-b border-gray-100 dark:border-gray-800", children: [e.jsx("div", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-1", children: "\u6708\u3005\u53CE\u652F" }), e.jsxs("div", { className: `text-4xl font-bold tracking-tight ${z.monthlyCf < 0 ? "text-rose-500" : "text-emerald-600 dark:text-emerald-400"}`, children: [z.monthlyCf < 0 ? "\u2212" : "+", "\xA5", b(Math.abs(z.monthlyCf))] })] }), e.jsxs("div", { className: "px-4 py-4 border-b border-gray-100 dark:border-gray-800 flex justify-between items-center", children: [e.jsx("span", { className: "text-[15px] text-gray-600 dark:text-gray-300", children: "\u5E74\u9593\u53C