function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
var _React = React,
useState = _React.useState,
useMemo = _React.useMemo;
var _Recharts = Recharts,
BarChart = _Recharts.BarChart,
Bar = _Recharts.Bar,
XAxis = _Recharts.XAxis,
YAxis = _Recharts.YAxis,
CartesianGrid = _Recharts.CartesianGrid,
Tooltip = _Recharts.Tooltip,
ResponsiveContainer = _Recharts.ResponsiveContainer,
Legend = _Recharts.Legend;
// ── Tokens ──
var T = {
bg: "#080C14",
surface: "#0E1520",
card: "#111827",
border: "#1E2D42",
border2: "#243348",
text: "#E8EEF7",
muted: "#5A7394",
dim: "#2E4060",
amber: "#F0A500",
emerald: "#10C980",
rose: "#F0445A",
sky: "#38BDF8",
violet: "#A78BFA",
orange: "#FB923C",
BDL: "#38BDF8",
Kids: "#A78BFA",
GB: "#10C980",
RES: "#FB923C"
};
var BUS = ["BDL", "Kids", "GB", "RES"];
var BUL = {
BDL: "Brooklyn Dance",
Kids: "Kids",
GB: "Green Boutique",
RES: "Residential"
};
var PTYPES = ["one-off", "installment", "subscription", "event-deposit", "event-balance"];
var PLBL = {
"one-off": "One-off",
installment: "Installment",
subscription: "Subscription",
"event-deposit": "Event Deposit",
"event-balance": "Event Balance"
};
var CATS = ["Classes", "Coaching", "Workshop", "Membership", "Rental / Event", "Consulting", "Semester", "Retainer", "Other"];
var SRCS = ["Stripe – BDL", "Stripe – GB", "Zelle", "Manual", "Sawyer"];
var MO = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var REF = "2025-05-20";
var $ = function $(n) {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 0
}).format(n || 0);
};
var $$ = function $$(n) {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
}).format(n || 0);
};
var fd = function fd(s) {
return new Date(s + "T00:00:00").toLocaleDateString("en-US", {
month: "short",
day: "numeric"
});
};
var fdl = function fdl(s) {
return new Date(s + "T00:00:00").toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric"
});
};
var now = function now() {
return new Date().toISOString().split("T")[0];
};
var addMo = function addMo(s, n) {
var d = new Date(s + "T00:00:00");
d.setMonth(d.getMonth() + n);
return d.toISOString().split("T")[0];
};
var dAway = function dAway(a, b) {
return Math.round((new Date(b + "T00:00:00") - new Date(a + "T00:00:00")) / 864e5);
};
var _c = 10,
_p = 10,
_t = 20,
_s = 100;
var cid = function cid() {
return "C".concat(String(++_c).padStart(3, "0"));
};
var pid = function pid() {
return "P".concat(String(++_p).padStart(3, "0"));
};
var tid = function tid() {
return "T".concat(String(++_t).padStart(3, "0"));
};
var sid = function sid() {
return "SP".concat(String(++_s).padStart(3, "0"));
};
// ── Seed Data ──
var SC = [{
id: "C001",
name: "Jane Smith",
bus: ["BDL"]
}, {
id: "C002",
name: "Bob Johnson",
bus: ["BDL"]
}, {
id: "C003",
name: "Carol White",
bus: ["BDL"]
}, {
id: "C004",
name: "David Lee",
bus: ["Kids"]
}, {
id: "C005",
name: "Eve Davis",
bus: ["GB"]
}, {
id: "C006",
name: "Frank Miller",
bus: ["BDL"]
}, {
id: "C007",
name: "Grace Chen",
bus: ["Kids"]
}, {
id: "C008",
name: "Hana Park",
bus: ["RES"]
}, {
id: "C009",
name: "Ivan Russo",
bus: ["GB"]
}];
var SP = [{
id: "P001",
clientId: "C001",
bu: "BDL",
type: "installment",
category: "Coaching",
label: "Coaching 3mo",
payments: [{
id: "SP001",
dueDate: "2025-05-03",
amount: 250,
status: "received",
txId: "T001"
}, {
id: "SP002",
dueDate: "2025-06-03",
amount: 250,
status: "scheduled",
txId: null
}, {
id: "SP003",
dueDate: "2025-07-03",
amount: 250,
status: "scheduled",
txId: null
}]
}, {
id: "P002",
clientId: "C003",
bu: "BDL",
type: "subscription",
category: "Membership",
label: "Monthly membership",
payments: [{
id: "SP010",
dueDate: "2025-05-10",
amount: 99,
status: "received",
txId: "T005"
}, {
id: "SP011",
dueDate: "2025-06-10",
amount: 99,
status: "scheduled",
txId: null
}, {
id: "SP012",
dueDate: "2025-07-10",
amount: 99,
status: "scheduled",
txId: null
}, {
id: "SP013",
dueDate: "2025-08-10",
amount: 99,
status: "scheduled",
txId: null
}]
}, {
id: "P003",
clientId: "C007",
bu: "Kids",
type: "installment",
category: "Semester",
label: "Spring semester 4mo",
payments: [{
id: "SP020",
dueDate: "2025-05-01",
amount: 275,
status: "received",
txId: "T008"
}, {
id: "SP021",
dueDate: "2025-06-01",
amount: 275,
status: "scheduled",
txId: null
}, {
id: "SP022",
dueDate: "2025-07-01",
amount: 275,
status: "scheduled",
txId: null
}, {
id: "SP023",
dueDate: "2025-08-01",
amount: 275,
status: "scheduled",
txId: null
}]
}, {
id: "P004",
clientId: "C008",
bu: "RES",
type: "event-deposit",
category: "Rental / Event",
label: "Room rental Jun 14",
minBalance: 600,
payments: [{
id: "SP030",
dueDate: "2025-05-15",
amount: 400,
status: "received",
txId: "T010"
}, {
id: "SP031",
dueDate: "2025-06-10",
amount: 600,
status: "scheduled",
txId: null,
isBalance: true
}]
}, {
id: "P005",
clientId: "C006",
bu: "BDL",
type: "subscription",
category: "Membership",
label: "Monthly membership",
payments: [{
id: "SP040",
dueDate: "2025-05-01",
amount: 99,
status: "received",
txId: "T009"
}, {
id: "SP041",
dueDate: "2025-06-01",
amount: 99,
status: "scheduled",
txId: null
}, {
id: "SP042",
dueDate: "2025-07-01",
amount: 99,
status: "scheduled",
txId: null
}]
}, {
id: "P006",
clientId: "C009",
bu: "GB",
type: "installment",
category: "Coaching",
label: "Wellness coaching 4mo",
payments: [{
id: "SP050",
dueDate: "2025-06-01",
amount: 320,
status: "scheduled",
txId: null
}, {
id: "SP051",
dueDate: "2025-07-01",
amount: 320,
status: "scheduled",
txId: null
}, {
id: "SP052",
dueDate: "2025-08-01",
amount: 320,
status: "scheduled",
txId: null
}, {
id: "SP053",
dueDate: "2025-09-01",
amount: 320,
status: "scheduled",
txId: null
}]
}];
var ST = [{
id: "T001",
date: "2025-05-03",
amount: 250,
src: "Stripe – BDL",
cId: "C001",
bu: "BDL",
pId: "P001",
type: "installment",
cat: "Coaching",
desc: "Coaching pkg 1/3",
st: "categorized",
fee: 7.55
}, {
id: "T002",
date: "2025-05-05",
amount: 1200,
src: "Zelle",
cId: "C002",
bu: "BDL",
pId: null,
type: "one-off",
cat: "Workshop",
desc: "Spring workshop",
st: "categorized",
fee: 0
}, {
id: "T003",
date: "2025-05-08",
amount: 350,
src: "Sawyer",
cId: "C004",
bu: "Kids",
pId: null,
type: "one-off",
cat: "Classes",
desc: "Kids class pack",
st: "categorized",
fee: 10.45
}, {
id: "T004",
date: "2025-05-12",
amount: 800,
src: "Manual",
cId: "C005",
bu: "GB",
pId: null,
type: "one-off",
cat: "Consulting",
desc: "Strategy session",
st: "categorized",
fee: 0
}, {
id: "T005",
date: "2025-05-10",
amount: 99,
src: "Stripe – BDL",
cId: "C003",
bu: "BDL",
pId: "P002",
type: "subscription",
cat: "Membership",
desc: "Membership May",
st: "categorized",
fee: 3.17
}, {
id: "T006",
date: "2025-05-14",
amount: 450,
src: "Stripe – BDL",
cId: null,
bu: null,
pId: null,
type: null,
cat: null,
desc: "Payment from customer",
st: "inbox",
fee: 13.35
}, {
id: "T007",
date: "2025-05-16",
amount: 180,
src: "Stripe – GB",
cId: null,
bu: null,
pId: null,
type: null,
cat: null,
desc: "GB wellness session",
st: "inbox",
fee: 5.52
}, {
id: "T008",
date: "2025-05-01",
amount: 275,
src: "Stripe – BDL",
cId: "C007",
bu: "Kids",
pId: "P003",
type: "installment",
cat: "Semester",
desc: "Semester 1/4",
st: "categorized",
fee: 8.27
}, {
id: "T009",
date: "2025-05-01",
amount: 99,
src: "Stripe – BDL",
cId: "C006",
bu: "BDL",
pId: "P005",
type: "subscription",
cat: "Membership",
desc: "Membership May",
st: "categorized",
fee: 3.17
}, {
id: "T010",
date: "2025-05-15",
amount: 400,
src: "Stripe – BDL",
cId: "C008",
bu: "RES",
pId: "P004",
type: "event-deposit",
cat: "Rental / Event",
desc: "Room rental deposit",
st: "categorized",
fee: 11.9
}, {
id: "T011",
date: "2025-05-18",
amount: 225,
src: "Stripe – BDL",
cId: null,
bu: null,
pId: null,
type: null,
cat: null,
desc: "Dance class reg",
st: "inbox",
fee: 6.82
}];
var SE = [{
id: "E001",
name: "Stripe Fees",
amount: 87.5,
cat: "Processing",
freq: "Monthly",
vendor: "Stripe"
}, {
id: "E002",
name: "Software",
amount: 150,
cat: "Software",
freq: "Monthly",
vendor: "Various"
}, {
id: "E003",
name: "Sawyer",
amount: 199,
cat: "Platform",
freq: "Monthly",
vendor: "Sawyer"
}, {
id: "E004",
name: "Marketing",
amount: 200,
cat: "Marketing",
freq: "Monthly",
vendor: "Meta/Google"
}, {
id: "E005",
name: "Contractor",
amount: 500,
cat: "Payroll",
freq: "Monthly",
vendor: "Staff"
}];
var SA = [{
id: "sa-1",
label: "Brooklyn Dance Lessons",
key: "",
lastSync: null,
status: "idle"
}, {
id: "sa-2",
label: "Green Boutique",
key: "",
lastSync: null,
status: "idle"
}];
// ── Engine ──
var allSP = function allSP(plans) {
return plans.flatMap(function (p) {
return p.payments.map(function (sp) {
return _objectSpread(_objectSpread({}, sp), {}, {
planId: p.id,
planLabel: p.label,
bu: p.bu,
clientId: p.clientId,
planType: p.type,
category: p.category
});
});
});
};
var upcoming = function upcoming(plans, days) {
var ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : REF;
var e = new Date(ref + "T00:00:00");
e.setDate(e.getDate() + days);
var es = e.toISOString().split("T")[0];
return allSP(plans).filter(function (sp) {
return sp.status === "scheduled" && sp.dueDate >= ref && sp.dueDate <= es;
});
};
var moChart = function moChart(plans, txns) {
return MO.map(function (name, i) {
return {
name: name,
confirmed: txns.filter(function (t) {
return t.st === "categorized" && new Date(t.date + "T00:00:00").getMonth() === i && new Date(t.date + "T00:00:00").getFullYear() === 2025;
}).reduce(function (s, t) {
return s + t.amount;
}, 0),
expected: allSP(plans).filter(function (sp) {
return sp.status === "scheduled" && new Date(sp.dueDate + "T00:00:00").getMonth() === i && new Date(sp.dueDate + "T00:00:00").getFullYear() === 2025;
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0)
};
});
};
// ── Style helpers ──
var S = {
card: {
background: T.card,
borderRadius: 12,
border: "1px solid ".concat(T.border),
padding: 20
},
inp: {
width: "100%",
background: T.surface,
border: "1px solid ".concat(T.border2),
borderRadius: 8,
padding: "9px 12px",
color: T.text,
fontSize: 13,
outline: "none",
boxSizing: "border-box",
fontFamily: "inherit"
},
lbl: {
fontSize: 11,
color: T.muted,
fontWeight: 700,
marginBottom: 5,
display: "block",
textTransform: "uppercase",
letterSpacing: 0.8
},
btn: function btn(bg) {
var fg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "#000";
return {
background: bg,
color: fg,
border: "none",
borderRadius: 8,
padding: "9px 18px",
cursor: "pointer",
fontWeight: 700,
fontSize: 13,
fontFamily: "inherit"
};
},
ghost: {
background: "transparent",
color: T.muted,
border: "1px solid ".concat(T.border2),
borderRadius: 8,
padding: "8px 14px",
cursor: "pointer",
fontSize: 12,
fontFamily: "inherit"
},
tag: function tag(c) {
return {
background: c + "18",
color: c,
border: "1px solid ".concat(c, "33"),
borderRadius: 5,
padding: "2px 9px",
fontSize: 11,
fontWeight: 700,
whiteSpace: "nowrap",
display: "inline-block"
};
}
};
var FF = function FF(_ref) {
var label = _ref.label,
children = _ref.children;
return /*#__PURE__*/React.createElement("div", {
style: {
marginBottom: 14
}
}, /*#__PURE__*/React.createElement("label", {
style: S.lbl
}, label), children);
};
var FS = function FS(_ref2) {
var value = _ref2.value,
_onChange = _ref2.onChange,
options = _ref2.options;
return /*#__PURE__*/React.createElement("select", {
value: value,
onChange: function onChange(e) {
return _onChange(e.target.value);
},
style: S.inp
}, options.map(function (o) {
return /*#__PURE__*/React.createElement("option", {
key: Array.isArray(o) ? o[0] : o,
value: Array.isArray(o) ? o[0] : o
}, Array.isArray(o) ? o[1] : o);
}));
};
var TH = function TH(_ref3) {
var c = _ref3.c;
return /*#__PURE__*/React.createElement("th", {
style: {
padding: "10px 14px",
textAlign: "left",
color: T.muted,
fontWeight: 700,
fontSize: 11,
textTransform: "uppercase",
letterSpacing: 0.8,
borderBottom: "1px solid ".concat(T.border)
}
}, c);
};
var TD = function TD(_ref4) {
var children = _ref4.children,
s = _ref4.s;
return /*#__PURE__*/React.createElement("td", {
style: _objectSpread({
padding: "11px 14px",
borderBottom: "1px solid ".concat(T.border),
verticalAlign: "middle"
}, s)
}, children);
};
var BUTag = function BUTag(_ref5) {
var bu = _ref5.bu;
return /*#__PURE__*/React.createElement("span", {
style: S.tag(T[bu] || T.muted)
}, BUL[bu] || bu || "—");
};
var TTag = function TTag(_ref6) {
var type = _ref6.type;
var c = {
"one-off": T.sky,
installment: T.amber,
subscription: T.emerald,
"event-deposit": T.violet,
"event-balance": T.orange
}[type] || T.muted;
return /*#__PURE__*/React.createElement("span", {
style: S.tag(c)
}, PLBL[type] || "—");
};
var Dot = function Dot(_ref7) {
var s = _ref7.s;
var c = {
received: T.emerald,
scheduled: T.amber,
overdue: T.rose,
categorized: T.emerald,
inbox: T.amber
}[s] || T.muted;
return /*#__PURE__*/React.createElement("span", {
style: {
display: "inline-flex",
alignItems: "center",
gap: 5,
fontSize: 12,
color: c,
fontWeight: 600
}
}, /*#__PURE__*/React.createElement("span", {
style: {
width: 6,
height: 6,
borderRadius: "50%",
background: c,
display: "inline-block"
}
}), s);
};
function KPI(_ref8) {
var label = _ref8.label,
value = _ref8.value,
sub = _ref8.sub,
color = _ref8.color,
icon = _ref8.icon;
return /*#__PURE__*/React.createElement("div", {
style: _objectSpread(_objectSpread({}, S.card), {}, {
borderTop: "2px solid ".concat(color),
flex: 1,
minWidth: 130
})
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted,
fontWeight: 700,
marginBottom: 8,
textTransform: "uppercase",
letterSpacing: 1
}
}, icon && /*#__PURE__*/React.createElement("span", {
style: {
marginRight: 5
}
}, icon), label), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 24,
fontWeight: 800,
color: T.text,
fontFamily: "'DM Mono',monospace",
letterSpacing: -1
}
}, value), sub && /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted,
marginTop: 5
}
}, sub));
}
function Modal(_ref9) {
var title = _ref9.title,
onClose = _ref9.onClose,
children = _ref9.children,
_ref9$width = _ref9.width,
width = _ref9$width === void 0 ? 580 : _ref9$width;
return /*#__PURE__*/React.createElement("div", {
style: {
position: "fixed",
inset: 0,
background: "rgba(0,0,0,0.75)",
zIndex: 200,
display: "flex",
alignItems: "center",
justifyContent: "center"
},
onClick: onClose
}, /*#__PURE__*/React.createElement("div", {
style: {
background: T.card,
borderRadius: 16,
padding: 28,
width: width,
maxWidth: "96vw",
border: "1px solid ".concat(T.border2),
maxHeight: "92vh",
overflowY: "auto",
boxShadow: "0 24px 80px rgba(0,0,0,0.6)"
},
onClick: function onClick(e) {
return e.stopPropagation();
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 22
}
}, /*#__PURE__*/React.createElement("h3", {
style: {
color: T.text,
margin: 0,
fontSize: 16,
fontWeight: 800,
fontFamily: "'Syne',sans-serif"
}
}, title), /*#__PURE__*/React.createElement("button", {
onClick: onClose,
style: {
background: "none",
border: "none",
color: T.muted,
cursor: "pointer",
fontSize: 22
}
}, "\u2715")), children));
}
function SH(_ref0) {
var title = _ref0.title,
action = _ref0.action;
return /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 16
}
}, /*#__PURE__*/React.createElement("h2", {
style: {
margin: 0,
fontSize: 15,
fontWeight: 800,
color: T.text,
fontFamily: "'Syne',sans-serif"
}
}, title), action);
}
// ── Categorize Modal ──
function CatModal(_ref1) {
var tx = _ref1.tx,
clients = _ref1.clients,
plans = _ref1.plans,
onSave = _ref1.onSave,
onClose = _ref1.onClose;
var _useState = useState(tx.bu || ""),
_useState2 = _slicedToArray(_useState, 2),
bu = _useState2[0],
setBu = _useState2[1];
var _useState3 = useState(tx.cId || ""),
_useState4 = _slicedToArray(_useState3, 2),
cId = _useState4[0],
setCId = _useState4[1];
var _useState5 = useState(""),
_useState6 = _slicedToArray(_useState5, 2),
newC = _useState6[0],
setNewC = _useState6[1];
var _useState7 = useState(tx.type || "one-off"),
_useState8 = _slicedToArray(_useState7, 2),
type = _useState8[0],
setType = _useState8[1];
var _useState9 = useState(tx.cat || "Classes"),
_useState0 = _slicedToArray(_useState9, 2),
cat = _useState0[0],
setCat = _useState0[1];
var _useState1 = useState(3),
_useState10 = _slicedToArray(_useState1, 2),
n = _useState10[0],
setN = _useState10[1];
var _useState11 = useState(true),
_useState12 = _slicedToArray(_useState11, 2),
same = _useState12[0],
setSame = _useState12[1];
var _useState13 = useState([tx.amount, tx.amount, tx.amount]),
_useState14 = _slicedToArray(_useState13, 2),
amts = _useState14[0],
setAmts = _useState14[1];
var _useState15 = useState(new Date(tx.date + "T00:00:00").getDate()),
_useState16 = _slicedToArray(_useState15, 2),
dom = _useState16[0],
setDom = _useState16[1];
var _useState17 = useState(0),
_useState18 = _slicedToArray(_useState17, 2),
minBal = _useState18[0],
setMinBal = _useState18[1];
var _useState19 = useState(""),
_useState20 = _slicedToArray(_useState19, 2),
balDue = _useState20[0],
setBalDue = _useState20[1];
var _useState21 = useState(tx.pId || ""),
_useState22 = _slicedToArray(_useState21, 2),
pId = _useState22[0],
setPId = _useState22[1];
var _useState23 = useState(""),
_useState24 = _slicedToArray(_useState23, 2),
notes = _useState24[0],
setNotes = _useState24[1];
function buildDates(count, start, day) {
var b = new Date(start + "T00:00:00");
b.setDate(day);
if (b < new Date(start + "T00:00:00")) b.setMonth(b.getMonth() + 1);
return Array(count).fill(0).map(function (_, i) {
var d = new Date(b);
d.setMonth(b.getMonth() + i);
return d.toISOString().split("T")[0];
});
}
function save() {
var uPlans = plans,
nPlan = null,
rPId = pId,
rSId = null,
nClients = clients,
rCId = cId;
if (!cId && newC.trim()) {
var nc = {
id: cid(),
name: newC.trim(),
bus: bu ? [bu] : []
};
nClients = [].concat(_toConsumableArray(clients), [nc]);
rCId = nc.id;
}
if (type === "installment" || type === "subscription") {
var count = type === "subscription" ? n + 3 : n;
var dates = buildDates(count, tx.date, dom);
var pmts = dates.map(function (d, i) {
return {
id: sid(),
dueDate: d,
amount: same ? tx.amount : amts[i] || tx.amount,
status: i === 0 ? "received" : "scheduled",
txId: i === 0 ? tx.id : null
};
});
rSId = pmts[0].id;
nPlan = {
id: pid(),
clientId: rCId,
bu: bu,
type: type,
category: cat,
label: "".concat(cat, " \u2013 ").concat(tx.date),
payments: pmts
};
rPId = nPlan.id;
uPlans = [].concat(_toConsumableArray(plans), [nPlan]);
} else if (type === "event-deposit") {
var _pmts = [{
id: sid(),
dueDate: tx.date,
amount: tx.amount,
status: "received",
txId: tx.id
}, {
id: sid(),
dueDate: balDue,
amount: parseFloat(minBal) || 0,
status: "scheduled",
txId: null,
isBalance: true
}];
rSId = _pmts[0].id;
nPlan = {
id: pid(),
clientId: rCId,
bu: bu,
type: type,
category: cat,
label: "Event \u2013 ".concat(tx.date),
minBalance: parseFloat(minBal),
payments: _pmts
};
rPId = nPlan.id;
uPlans = [].concat(_toConsumableArray(plans), [nPlan]);
} else if (type === "event-balance" && pId) {
uPlans = plans.map(function (p) {
return p.id !== pId ? p : _objectSpread(_objectSpread({}, p), {}, {
payments: p.payments.map(function (sp) {
return sp.isBalance ? _objectSpread(_objectSpread({}, sp), {}, {
status: "received",
txId: tx.id
}) : sp;
})
});
});
}
onSave({
tx: _objectSpread(_objectSpread({}, tx), {}, {
bu: bu,
cId: rCId,
pId: rPId,
type: type,
cat: cat,
notes: notes,
st: "categorized"
}),
plans: uPlans,
clients: nClients
});
}
return /*#__PURE__*/React.createElement(Modal, {
title: "Categorize \u2014 ".concat($$(tx.amount)),
onClose: onClose,
width: 620
}, /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderRadius: 10,
padding: "12px 16px",
marginBottom: 20,
display: "flex",
gap: 20,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Source"), /*#__PURE__*/React.createElement("span", {
style: S.tag(T.sky)
}, tx.src)), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Date"), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 13
}
}, fdl(tx.date))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Amount"), /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 800,
fontSize: 16,
color: T.emerald
}
}, $$(tx.amount))), tx.fee > 0 && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Fee"), /*#__PURE__*/React.createElement("div", {
style: {
color: T.muted,
fontSize: 13
}
}, "\u2212", $$(tx.fee))), /*#__PURE__*/React.createElement("div", {
style: {
flex: 1
}
}, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Description"), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 13
}
}, tx.desc))), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0 16px"
}
}, /*#__PURE__*/React.createElement(FF, {
label: "Business Unit"
}, /*#__PURE__*/React.createElement(FS, {
value: bu,
onChange: setBu,
options: [["", "Select BU…"]].concat(_toConsumableArray(BUS.map(function (b) {
return [b, BUL[b]];
})))
})), /*#__PURE__*/React.createElement(FF, {
label: "Category"
}, /*#__PURE__*/React.createElement(FS, {
value: cat,
onChange: setCat,
options: CATS
})), /*#__PURE__*/React.createElement(FF, {
label: "Client"
}, /*#__PURE__*/React.createElement("select", {
value: cId,
onChange: function onChange(e) {
return setCId(e.target.value);
},
style: S.inp
}, /*#__PURE__*/React.createElement("option", {
value: ""
}, "\u2014 Select or create \u2014"), clients.filter(function (c) {
return !bu || c.bus.includes(bu);
}).map(function (c) {
return /*#__PURE__*/React.createElement("option", {
key: c.id,
value: c.id
}, c.name, " (", c.id, ")");
}), /*#__PURE__*/React.createElement("option", {
value: "__new__"
}, "+ Create new"))), cId === "__new__" && /*#__PURE__*/React.createElement(FF, {
label: "New Client Name"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: newC,
onChange: function onChange(e) {
return setNewC(e.target.value);
},
placeholder: "Full name"
})), /*#__PURE__*/React.createElement(FF, {
label: "Type"
}, /*#__PURE__*/React.createElement(FS, {
value: type,
onChange: setType,
options: PTYPES.map(function (t) {
return [t, PLBL[t]];
})
}))), (type === "installment" || type === "subscription") && /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderRadius: 10,
padding: 16,
marginBottom: 14
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted,
fontWeight: 700,
marginBottom: 12,
textTransform: "uppercase",
letterSpacing: 0.8
}
}, "Plan Setup \u2014 this tx = payment 1"), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gap: "0 16px"
}
}, /*#__PURE__*/React.createElement(FF, {
label: "# Payments"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: n,
min: 1,
onChange: function onChange(e) {
var v = parseInt(e.target.value) || 1;
setN(v);
setAmts(Array(v).fill(tx.amount));
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Day of Month"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: dom,
min: 1,
max: 28,
onChange: function onChange(e) {
return setDom(parseInt(e.target.value) || 1);
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Amounts"
}, /*#__PURE__*/React.createElement(FS, {
value: same ? "same" : "var",
onChange: function onChange(v) {
return setSame(v === "same");
},
options: [["same", "Same"], ["var", "Variable"]]
}))), !same && /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "repeat(auto-fill,minmax(90px,1fr))",
gap: 8
}
}, Array(n).fill(0).map(function (_, i) {
return /*#__PURE__*/React.createElement("div", {
key: i
}, /*#__PURE__*/React.createElement("div", {
style: _objectSpread(_objectSpread({}, S.lbl), {}, {
marginBottom: 3
})
}, "Pmt ", i + 1), /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: amts[i] || "",
onChange: function onChange(e) {
var a = _toConsumableArray(amts);
a[i] = parseFloat(e.target.value) || 0;
setAmts(a);
}
}));
}))), type === "event-deposit" && /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderRadius: 10,
padding: 16,
marginBottom: 14
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted,
fontWeight: 700,
marginBottom: 12,
textTransform: "uppercase",
letterSpacing: 0.8
}
}, "Event Balance Setup"), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0 16px"
}
}, /*#__PURE__*/React.createElement(FF, {
label: "Min Balance ($)"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: minBal,
onChange: function onChange(e) {
return setMinBal(e.target.value);
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Balance Due Date"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "date",
value: balDue,
onChange: function onChange(e) {
return setBalDue(e.target.value);
}
})))), type === "event-balance" && /*#__PURE__*/React.createElement(FF, {
label: "Link to Event Deposit"
}, /*#__PURE__*/React.createElement("select", {
value: pId,
onChange: function onChange(e) {
return setPId(e.target.value);
},
style: S.inp
}, /*#__PURE__*/React.createElement("option", {
value: ""
}, "\u2014 Select deposit \u2014"), plans.filter(function (p) {
return p.type === "event-deposit";
}).map(function (p) {
return /*#__PURE__*/React.createElement("option", {
key: p.id,
value: p.id
}, p.label);
}))), /*#__PURE__*/React.createElement(FF, {
label: "Notes"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: notes,
onChange: function onChange(e) {
return setNotes(e.target.value);
},
placeholder: "Optional"
})), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
justifyContent: "flex-end",
marginTop: 8
}
}, /*#__PURE__*/React.createElement("button", {
onClick: onClose,
style: S.ghost
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
onClick: save,
style: S.btn(T.amber)
}, "Save")));
}
// ── Add Plan Modal ──
function PlanModal(_ref10) {
var clients = _ref10.clients,
onSave = _ref10.onSave,
onClose = _ref10.onClose;
var _useState25 = useState("BDL"),
_useState26 = _slicedToArray(_useState25, 2),
bu = _useState26[0],
setBu = _useState26[1];
var _useState27 = useState(""),
_useState28 = _slicedToArray(_useState27, 2),
cId = _useState28[0],
setCId = _useState28[1];
var _useState29 = useState(""),
_useState30 = _slicedToArray(_useState29, 2),
newC = _useState30[0],
setNewC = _useState30[1];
var _useState31 = useState("installment"),
_useState32 = _slicedToArray(_useState31, 2),
type = _useState32[0],
setType = _useState32[1];
var _useState33 = useState("Coaching"),
_useState34 = _slicedToArray(_useState33, 2),
cat = _useState34[0],
setCat = _useState34[1];
var _useState35 = useState(""),
_useState36 = _slicedToArray(_useState35, 2),
label = _useState36[0],
setLabel = _useState36[1];
var _useState37 = useState(""),
_useState38 = _slicedToArray(_useState37, 2),
amt = _useState38[0],
setAmt = _useState38[1];
var _useState39 = useState(3),
_useState40 = _slicedToArray(_useState39, 2),
n = _useState40[0],
setN = _useState40[1];
var _useState41 = useState(now()),
_useState42 = _slicedToArray(_useState41, 2),
start = _useState42[0],
setStart = _useState42[1];
var _useState43 = useState(new Date().getDate()),
_useState44 = _slicedToArray(_useState43, 2),
dom = _useState44[0],
setDom = _useState44[1];
var _useState45 = useState(""),
_useState46 = _slicedToArray(_useState45, 2),
minBal = _useState46[0],
setMin = _useState46[1];
var _useState47 = useState(""),
_useState48 = _slicedToArray(_useState47, 2),
balDue = _useState48[0],
setBal = _useState48[1];
function save() {
var amount = parseFloat(amt) || 0;
var pmts = [],
nClients = clients,
rCId = cId;
if (!cId && newC.trim()) {
var nc = {
id: cid(),
name: newC.trim(),
bus: [bu]
};
nClients = [].concat(_toConsumableArray(clients), [nc]);
rCId = nc.id;
}
function dates(count) {
var b = new Date(start + "T00:00:00");
b.setDate(dom);
if (b < new Date(start + "T00:00:00")) b.setMonth(b.getMonth() + 1);
return Array(count).fill(0).map(function (_, i) {
var d = new Date(b);
d.setMonth(b.getMonth() + i);
return d.toISOString().split("T")[0];
});
}
if (type === "installment" || type === "subscription") {
pmts = dates(type === "subscription" ? n + 3 : n).map(function (d) {
return {
id: sid(),
dueDate: d,
amount: amount,
status: "scheduled",
txId: null
};
});
} else if (type === "event-deposit") {
pmts = [{
id: sid(),
dueDate: start,
amount: amount,
status: "scheduled",
txId: null
}, {
id: sid(),
dueDate: balDue,
amount: parseFloat(minBal) || 0,
status: "scheduled",
txId: null,
isBalance: true
}];
} else {
pmts = [{
id: sid(),
dueDate: start,
amount: amount,
status: "scheduled",
txId: null
}];
}
onSave({
plan: {
id: pid(),
clientId: rCId,
bu: bu,
type: type,
category: cat,
label: label || "".concat(cat, " \u2013 ").concat(start),
payments: pmts
},
clients: nClients
});
}
return /*#__PURE__*/React.createElement(Modal, {
title: "Add Payment Plan",
onClose: onClose
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0 16px"
}
}, /*#__PURE__*/React.createElement(FF, {
label: "BU"
}, /*#__PURE__*/React.createElement(FS, {
value: bu,
onChange: setBu,
options: BUS.map(function (b) {
return [b, BUL[b]];
})
})), /*#__PURE__*/React.createElement(FF, {
label: "Type"
}, /*#__PURE__*/React.createElement(FS, {
value: type,
onChange: setType,
options: PTYPES.map(function (t) {
return [t, PLBL[t]];
})
})), /*#__PURE__*/React.createElement(FF, {
label: "Client"
}, /*#__PURE__*/React.createElement("select", {
value: cId,
onChange: function onChange(e) {
return setCId(e.target.value);
},
style: S.inp
}, /*#__PURE__*/React.createElement("option", {
value: ""
}, "\u2014 Select or create \u2014"), clients.filter(function (c) {
return c.bus.includes(bu);
}).map(function (c) {
return /*#__PURE__*/React.createElement("option", {
key: c.id,
value: c.id
}, c.name);
}), /*#__PURE__*/React.createElement("option", {
value: "__new__"
}, "+ New client"))), cId === "__new__" && /*#__PURE__*/React.createElement(FF, {
label: "Client Name"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: newC,
onChange: function onChange(e) {
return setNewC(e.target.value);
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Category"
}, /*#__PURE__*/React.createElement(FS, {
value: cat,
onChange: setCat,
options: CATS
})), /*#__PURE__*/React.createElement(FF, {
label: "Label"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: label,
onChange: function onChange(e) {
return setLabel(e.target.value);
},
placeholder: "e.g. Spring semester"
})), /*#__PURE__*/React.createElement(FF, {
label: "Amount/pmt ($)"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: amt,
onChange: function onChange(e) {
return setAmt(e.target.value);
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Start Date"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "date",
value: start,
onChange: function onChange(e) {
return setStart(e.target.value);
}
})), (type === "installment" || type === "subscription") && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FF, {
label: "# Payments"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: n,
onChange: function onChange(e) {
return setN(parseInt(e.target.value) || 1);
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Day of Month"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: dom,
min: 1,
max: 28,
onChange: function onChange(e) {
return setDom(parseInt(e.target.value) || 1);
}
}))), type === "event-deposit" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FF, {
label: "Min Balance ($)"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: minBal,
onChange: function onChange(e) {
return setMin(e.target.value);
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Balance Due"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "date",
value: balDue,
onChange: function onChange(e) {
return setBal(e.target.value);
}
})))), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
justifyContent: "flex-end",
marginTop: 8
}
}, /*#__PURE__*/React.createElement("button", {
onClick: onClose,
style: S.ghost
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
onClick: save,
style: S.btn(T.emerald)
}, "Create Plan")));
}
// ── Main App ──
function App() {
var _useState49 = useState("dashboard"),
_useState50 = _slicedToArray(_useState49, 2),
tab = _useState50[0],
setTab = _useState50[1];
var _useState51 = useState(ST),
_useState52 = _slicedToArray(_useState51, 2),
txns = _useState52[0],
setTxns = _useState52[1];
var _useState53 = useState(SP),
_useState54 = _slicedToArray(_useState53, 2),
plans = _useState54[0],
setPlans = _useState54[1];
var _useState55 = useState(SC),
_useState56 = _slicedToArray(_useState55, 2),
clients = _useState56[0],
setClients = _useState56[1];
var _useState57 = useState(SE),
_useState58 = _slicedToArray(_useState57, 2),
exps = _useState58[0],
setExps = _useState58[1];
var _useState59 = useState(SA),
_useState60 = _slicedToArray(_useState59, 2),
stripeA = _useState60[0],
setStripeA = _useState60[1];
var _useState61 = useState(null),
_useState62 = _slicedToArray(_useState61, 2),
catTx = _useState62[0],
setCatTx = _useState62[1];
var _useState63 = useState(false),
_useState64 = _slicedToArray(_useState63, 2),
showPlan = _useState64[0],
setShowPlan = _useState64[1];
var _useState65 = useState(false),
_useState66 = _slicedToArray(_useState65, 2),
showAddTx = _useState66[0],
setShowAddTx = _useState66[1];
var _useState67 = useState(false),
_useState68 = _slicedToArray(_useState67, 2),
showAddExp = _useState68[0],
setShowAddExp = _useState68[1];
var _useState69 = useState([]),
_useState70 = _slicedToArray(_useState69, 2),
syncLog = _useState70[0],
setSyncLog = _useState70[1];
var _useState71 = useState(false),
_useState72 = _slicedToArray(_useState71, 2),
showLog = _useState72[0],
setShowLog = _useState72[1];
var _useState73 = useState("All"),
_useState74 = _slicedToArray(_useState73, 2),
rBU = _useState74[0],
setRBU = _useState74[1];
var _useState75 = useState("All"),
_useState76 = _slicedToArray(_useState75, 2),
rType = _useState76[0],
setRType = _useState76[1];
var _useState77 = useState("All"),
_useState78 = _slicedToArray(_useState77, 2),
txF = _useState78[0],
setTxF = _useState78[1];
var _useState79 = useState("All"),
_useState80 = _slicedToArray(_useState79, 2),
txBU = _useState80[0],
setTxBU = _useState80[1];
var _useState81 = useState(""),
_useState82 = _slicedToArray(_useState81, 2),
txQ = _useState82[0],
setTxQ = _useState82[1];
var bTx = {
date: now(),
amount: "",
src: "Stripe – BDL",
desc: "",
fee: 0,
st: "inbox",
bu: "",
cId: "",
pId: null,
type: null,
cat: null
};
var bExp = {
name: "",
amount: "",
cat: "Software",
freq: "Monthly",
vendor: ""
};
var _useState83 = useState(bTx),
_useState84 = _slicedToArray(_useState83, 2),
nTx = _useState84[0],
setNTx = _useState84[1];
var _useState85 = useState(bExp),
_useState86 = _slicedToArray(_useState85, 2),
nExp = _useState86[0],
setNExp = _useState86[1];
var inbox = useMemo(function () {
return txns.filter(function (t) {
return t.st === "inbox";
});
}, [txns]);
var done = useMemo(function () {
return txns.filter(function (t) {
return t.st === "categorized";
});
}, [txns]);
var aSP = useMemo(function () {
return allSP(plans);
}, [plans]);
var n7 = useMemo(function () {
return upcoming(plans, 7);
}, [plans]);
var n30 = useMemo(function () {
return upcoming(plans, 30);
}, [plans]);
var moD = useMemo(function () {
return moChart(plans, txns);
}, [plans, txns]);
var totExp = useMemo(function () {
return exps.reduce(function (s, e) {
return s + e.amount;
}, 0);
}, [exps]);
var curMo = new Date(REF + "T00:00:00").getMonth();
var curYr = new Date(REF + "T00:00:00").getFullYear();
var compMTD = useMemo(function () {
return done.filter(function (t) {
var d = new Date(t.date + "T00:00:00");
return d.getMonth() === curMo && d.getFullYear() === curYr;
}).reduce(function (s, t) {
return s + t.amount;
}, 0);
}, [done]);
var expMTD = useMemo(function () {
return aSP.filter(function (sp) {
var d = new Date(sp.dueDate + "T00:00:00");
return d.getMonth() === curMo && d.getFullYear() === curYr && sp.status === "scheduled";
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0);
}, [aSP]);
var buStats = useMemo(function () {
return BUS.map(function (bu) {
return {
bu: bu,
color: T[bu],
confirmed: aSP.filter(function (sp) {
return sp.bu === bu && sp.status === "received";
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0),
expected: aSP.filter(function (sp) {
return sp.bu === bu && sp.status === "scheduled";
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0)
};
});
}, [aSP]);
var filtTx = useMemo(function () {
return txns.filter(function (t) {
var _clients$find;
return (txF === "All" || t.st === txF) && (txBU === "All" || t.bu === txBU) && (!txQ || (t.desc || "").toLowerCase().includes(txQ.toLowerCase()) || (((_clients$find = clients.find(function (c) {
return c.id === t.cId;
})) === null || _clients$find === void 0 ? void 0 : _clients$find.name) || "").toLowerCase().includes(txQ.toLowerCase()));
});
}, [txns, txF, txBU, txQ, clients]);
var cn = function cn(id) {
var _clients$find2;
return ((_clients$find2 = clients.find(function (c) {
return c.id === id;
})) === null || _clients$find2 === void 0 ? void 0 : _clients$find2.name) || "—";
};
function saveCat(_ref11) {
var tx = _ref11.tx,
p2 = _ref11.plans,
c2 = _ref11.clients;
setTxns(function (prev) {
return prev.map(function (t) {
return t.id === tx.id ? tx : t;
});
});
setPlans(p2);
setClients(c2);
setCatTx(null);
}
function addPlan(_ref12) {
var plan = _ref12.plan,
c2 = _ref12.clients;
setPlans(function (prev) {
return [].concat(_toConsumableArray(prev), [plan]);
});
setClients(c2);
setShowPlan(false);
}
function addTx() {
if (!nTx.amount) return;
setTxns(function (prev) {
return [].concat(_toConsumableArray(prev), [_objectSpread(_objectSpread({}, nTx), {}, {
id: tid(),
amount: parseFloat(nTx.amount)
})]);
});
setNTx(bTx);
setShowAddTx(false);
}
function addExp() {
if (!nExp.amount || !nExp.name) return;
setExps(function (prev) {
return [].concat(_toConsumableArray(prev), [_objectSpread(_objectSpread({}, nExp), {}, {
id: "E".concat(exps.length + 1),
amount: parseFloat(nExp.amount)
})]);
});
setNExp(bExp);
setShowAddExp(false);
}
function markRcv(planId, spId) {
setPlans(function (prev) {
return prev.map(function (p) {
return p.id !== planId ? p : _objectSpread(_objectSpread({}, p), {}, {
payments: p.payments.map(function (sp) {
return sp.id !== spId ? sp : _objectSpread(_objectSpread({}, sp), {}, {
status: "received"
});
})
});
});
});
}
var Tip = function Tip(_ref13) {
var active = _ref13.active,
payload = _ref13.payload,
label = _ref13.label;
if (!active || !(payload !== null && payload !== void 0 && payload.length)) return null;
return /*#__PURE__*/React.createElement("div", {
style: {
background: T.card,
border: "1px solid ".concat(T.border2),
borderRadius: 10,
padding: "10px 14px",
fontSize: 12
}
}, /*#__PURE__*/React.createElement("div", {
style: {
color: T.muted,
marginBottom: 6,
fontWeight: 700
}
}, label), payload.map(function (p) {
return /*#__PURE__*/React.createElement("div", {
key: p.name,
style: {
color: p.color,
marginBottom: 2
}
}, p.name, ": ", /*#__PURE__*/React.createElement("strong", {
style: {
fontFamily: "'DM Mono',monospace"
}
}, $(p.value)));
}));
};
var Nav = function Nav(_ref14) {
var k = _ref14.k,
lbl = _ref14.lbl,
icon = _ref14.icon,
badge = _ref14.badge;
return /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setTab(k);
},
style: {
background: tab === k ? T.amber + "18" : "none",
color: tab === k ? T.amber : T.muted,
border: tab === k ? "1px solid ".concat(T.amber, "33") : "1px solid transparent",
borderRadius: 8,
padding: "7px 11px",
cursor: "pointer",
fontWeight: 700,
fontSize: 12,
display: "inline-flex",
alignItems: "center",
gap: 5,
fontFamily: "'Syne',sans-serif"
}
}, icon, " ", lbl, badge > 0 && /*#__PURE__*/React.createElement("span", {
style: {
background: T.rose,
color: "#fff",
borderRadius: 10,
padding: "1px 6px",
fontSize: 10,
fontWeight: 800
}
}, badge));
};
return /*#__PURE__*/React.createElement("div", {
style: {
minHeight: "100vh",
background: T.bg,
color: T.text,
fontFamily: "'DM Sans','Segoe UI',sans-serif"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderBottom: "1px solid ".concat(T.border),
padding: "0 20px",
display: "flex",
alignItems: "center",
gap: 10,
height: 56,
position: "sticky",
top: 0,
zIndex: 100,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'Syne',sans-serif",
fontWeight: 800,
fontSize: 16,
color: T.text,
display: "flex",
alignItems: "center",
gap: 6
}
}, /*#__PURE__*/React.createElement("span", {
style: {
color: T.amber
}
}, "\u25C8"), "FinanceOS"), /*#__PURE__*/React.createElement("div", {
style: {
width: 1,
height: 20,
background: T.border
}
}), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 2,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement(Nav, {
k: "dashboard",
lbl: "Dashboard",
icon: "\u25C9"
}), /*#__PURE__*/React.createElement(Nav, {
k: "inbox",
lbl: "Inbox",
icon: "\u25C8",
badge: inbox.length
}), /*#__PURE__*/React.createElement(Nav, {
k: "txns",
lbl: "Transactions",
icon: "\u2261"
}), /*#__PURE__*/React.createElement(Nav, {
k: "plans",
lbl: "Plans",
icon: "\u229E"
}), /*#__PURE__*/React.createElement(Nav, {
k: "clients",
lbl: "Clients",
icon: "\u25CE"
}), /*#__PURE__*/React.createElement(Nav, {
k: "reports",
lbl: "Reports",
icon: "\u229F"
}), /*#__PURE__*/React.createElement(Nav, {
k: "expenses",
lbl: "Expenses",
icon: "\u2193"
}), /*#__PURE__*/React.createElement(Nav, {
k: "sources",
lbl: "Sources",
icon: "\u27F3"
})), /*#__PURE__*/React.createElement("div", {
style: {
marginLeft: "auto",
display: "flex",
gap: 8
}
}, /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowAddTx(true);
},
style: _objectSpread(_objectSpread({}, S.ghost), {}, {
fontSize: 12
})
}, "+ Manual Tx"), /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowPlan(true);
},
style: S.btn(T.amber)
}, "+ Add Plan"))), /*#__PURE__*/React.createElement("div", {
style: {
padding: "20px",
maxWidth: 1360,
margin: "0 auto"
}
}, tab === "dashboard" && /*#__PURE__*/React.createElement("div", null, inbox.length > 0 && /*#__PURE__*/React.createElement("div", {
onClick: function onClick() {
return setTab("inbox");
},
style: {
background: T.amber + "12",
border: "1px solid ".concat(T.amber, "33"),
borderRadius: 10,
padding: "12px 16px",
marginBottom: 16,
display: "flex",
alignItems: "center",
gap: 12,
cursor: "pointer"
}
}, /*#__PURE__*/React.createElement("span", {
style: {
color: T.amber,
fontWeight: 700,
fontSize: 13
}
}, "\u25C8 ", inbox.length, " transaction", inbox.length > 1 ? "s" : "", " waiting to be categorized"), /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontSize: 12,
marginLeft: "auto"
}
}, "Go to Inbox \u2192")), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
marginBottom: 16,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement(KPI, {
label: "Confirmed MTD",
value: $(compMTD),
color: T.emerald,
icon: "\u2713",
sub: "".concat(done.filter(function (t) {
return new Date(t.date + "T00:00:00").getMonth() === curMo;
}).length, " transactions")
}), /*#__PURE__*/React.createElement(KPI, {
label: "Expected MTD",
value: $(expMTD),
color: T.amber,
icon: "\u25F7",
sub: "From scheduled plans"
}), /*#__PURE__*/React.createElement(KPI, {
label: "Next 7 Days",
value: $(n7.reduce(function (s, sp) {
return s + sp.amount;
}, 0)),
color: T.sky,
icon: "\u2192",
sub: "".concat(n7.length, " payments")
}), /*#__PURE__*/React.createElement(KPI, {
label: "Next 30 Days",
value: $(n30.reduce(function (s, sp) {
return s + sp.amount;
}, 0)),
color: T.violet,
icon: "\u22A1",
sub: "".concat(n30.length, " payments")
}), /*#__PURE__*/React.createElement(KPI, {
label: "Expenses/mo",
value: $(totExp),
color: T.rose,
icon: "\u2193"
}), /*#__PURE__*/React.createElement(KPI, {
label: "Net MTD",
value: $(compMTD - totExp),
color: compMTD - totExp >= 0 ? T.emerald : T.rose,
icon: "="
})), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "2fr 1fr",
gap: 14,
marginBottom: 14
}
}, /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: "Monthly Revenue \u2014 Confirmed vs Expected"
}), /*#__PURE__*/React.createElement(ResponsiveContainer, {
width: "100%",
height: 220
}, /*#__PURE__*/React.createElement(BarChart, {
data: moD,
barSize: 13,
barGap: 2
}, /*#__PURE__*/React.createElement(CartesianGrid, {
strokeDasharray: "3 3",
stroke: T.border,
vertical: false
}), /*#__PURE__*/React.createElement(XAxis, {
dataKey: "name",
tick: {
fill: T.muted,
fontSize: 11
},
axisLine: false,
tickLine: false
}), /*#__PURE__*/React.createElement(YAxis, {
tick: {
fill: T.muted,
fontSize: 11
},
axisLine: false,
tickLine: false,
tickFormatter: function tickFormatter(v) {
return "$" + (v / 1000).toFixed(0) + "k";
}
}), /*#__PURE__*/React.createElement(Tooltip, {
content: /*#__PURE__*/React.createElement(Tip, null)
}), /*#__PURE__*/React.createElement(Legend, {
wrapperStyle: {
fontSize: 12,
color: T.muted,
paddingTop: 8
}
}), /*#__PURE__*/React.createElement(Bar, {
dataKey: "confirmed",
name: "Confirmed",
fill: T.emerald,
radius: [4, 4, 0, 0]
}), /*#__PURE__*/React.createElement(Bar, {
dataKey: "expected",
name: "Expected",
fill: T.amber,
radius: [4, 4, 0, 0],
fillOpacity: 0.7
})))), /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: "By Business Unit"
}), buStats.map(function (b) {
var total = b.confirmed + b.expected;
var max = Math.max.apply(Math, _toConsumableArray(buStats.map(function (x) {
return x.confirmed + x.expected;
})).concat([1]));
return /*#__PURE__*/React.createElement("div", {
key: b.bu,
style: {
marginBottom: 14
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
marginBottom: 4
}
}, /*#__PURE__*/React.createElement("span", {
style: {
fontSize: 12,
fontWeight: 700,
color: b.color
}
}, BUL[b.bu]), /*#__PURE__*/React.createElement("span", {
style: {
fontSize: 12,
fontFamily: "'DM Mono',monospace",
color: T.muted
}
}, /*#__PURE__*/React.createElement("span", {
style: {
color: T.text
}
}, $(b.confirmed)), b.expected > 0 && /*#__PURE__*/React.createElement("span", {
style: {
color: T.amber
}
}, " +", $(b.expected)))), /*#__PURE__*/React.createElement("div", {
style: {
height: 5,
background: T.border,
borderRadius: 3,
overflow: "hidden"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
height: "100%",
width: "".concat(total / max * 100, "%"),
background: b.color + "44",
borderRadius: 3,
position: "relative"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
position: "absolute",
left: 0,
top: 0,
height: "100%",
width: "".concat(total > 0 ? b.confirmed / total * 100 : 0, "%"),
background: b.color,
borderRadius: 3
}
}))));
}))), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: 14,
marginBottom: 14
}
}, [{
label: "Next 7 Days",
items: n7,
color: T.sky
}, {
label: "Next 30 Days",
items: n30,
color: T.violet
}].map(function (_ref15) {
var label = _ref15.label,
items = _ref15.items,
color = _ref15.color;
return /*#__PURE__*/React.createElement("div", {
key: label,
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: label,
action: /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 800,
color: color,
fontSize: 18
}
}, $(items.reduce(function (s, sp) {
return s + sp.amount;
}, 0)))
}), items.length === 0 && /*#__PURE__*/React.createElement("div", {
style: {
color: T.muted,
fontSize: 13,
textAlign: "center",
padding: "16px 0"
}
}, "No payments scheduled"), items.slice(0, 5).map(function (sp) {
return /*#__PURE__*/React.createElement("div", {
key: sp.id,
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
padding: "8px 0",
borderBottom: "1px solid ".concat(T.border)
}
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
fontWeight: 600,
fontSize: 13
}
}, cn(sp.clientId)), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted
}
}, sp.planLabel)), /*#__PURE__*/React.createElement("div", {
style: {
textAlign: "right"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
color: T.emerald,
fontSize: 14
}
}, $$(sp.amount)), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: color
}
}, fd(sp.dueDate), " \xB7 ", dAway(REF, sp.dueDate), "d")));
}), items.length > 5 && /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted,
marginTop: 8,
textAlign: "center"
}
}, "+", items.length - 5, " more"));
})), /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: "All Upcoming Scheduled Payments"
}), /*#__PURE__*/React.createElement("div", {
style: {
overflowX: "auto"
}
}, /*#__PURE__*/React.createElement("table", {
style: {
width: "100%",
borderCollapse: "collapse"
}
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement(TH, {
c: "Due"
}), /*#__PURE__*/React.createElement(TH, {
c: "Client"
}), /*#__PURE__*/React.createElement(TH, {
c: "Plan"
}), /*#__PURE__*/React.createElement(TH, {
c: "BU"
}), /*#__PURE__*/React.createElement(TH, {
c: "Type"
}), /*#__PURE__*/React.createElement(TH, {
c: "Amount"
}), /*#__PURE__*/React.createElement(TH, {
c: ""
}))), /*#__PURE__*/React.createElement("tbody", null, aSP.filter(function (sp) {
return sp.status === "scheduled";
}).sort(function (a, b) {
return a.dueDate.localeCompare(b.dueDate);
}).slice(0, 12).map(function (sp) {
var d = dAway(REF, sp.dueDate);
var urgent = d <= 7;
return /*#__PURE__*/React.createElement("tr", {
key: sp.id,
className: "rh"
}, /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontSize: 12,
color: urgent ? T.amber : T.text
}
}, fd(sp.dueDate)), urgent && /*#__PURE__*/React.createElement("span", {
style: _objectSpread(_objectSpread({}, S.tag(T.amber)), {}, {
marginLeft: 6,
fontSize: 10
})
}, d, "d")), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontWeight: 600,
fontSize: 13
}
}, cn(sp.clientId))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontSize: 12
}
}, sp.planLabel)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(BUTag, {
bu: sp.bu
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(TTag, {
type: sp.planType
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
color: T.emerald
}
}, $$(sp.amount))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return markRcv(sp.planId, sp.id);
},
style: _objectSpread(_objectSpread({}, S.btn(T.emerald + "22", T.emerald)), {}, {
padding: "4px 10px",
fontSize: 11,
border: "1px solid ".concat(T.emerald, "33")
})
}, "\u2713 Received")));
})))))), tab === "inbox" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(SH, {
title: "Inbox \u2014 ".concat(inbox.length, " uncategorized"),
action: /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 8
}
}, stripeA.map(function (a) {
return /*#__PURE__*/React.createElement("button", {
key: a.id,
style: _objectSpread(_objectSpread({}, S.ghost), {}, {
fontSize: 11,
display: "flex",
alignItems: "center",
gap: 5
})
}, /*#__PURE__*/React.createElement("span", {
style: {
color: {
idle: T.muted,
syncing: T.amber,
ok: T.emerald,
error: T.rose
}[a.status],
fontSize: 8
}
}, "\u25CF"), "Sync ", a.label.split(" ").map(function (w) {
return w[0];
}).join(""));
}))
}), /*#__PURE__*/React.createElement("p", {
style: {
color: T.muted,
fontSize: 13,
marginTop: -8,
marginBottom: 16
}
}, "Categorize each transaction to include it in your revenue data."), inbox.length === 0 ? /*#__PURE__*/React.createElement("div", {
style: _objectSpread(_objectSpread({}, S.card), {}, {
textAlign: "center",
padding: 40
})
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 32,
marginBottom: 10
}
}, "\u2713"), /*#__PURE__*/React.createElement("div", {
style: {
color: T.muted,
fontSize: 14,
fontWeight: 600
}
}, "Inbox clear.")) : /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
flexDirection: "column",
gap: 10
}
}, inbox.map(function (tx) {
return /*#__PURE__*/React.createElement("div", {
key: tx.id,
style: _objectSpread(_objectSpread({}, S.card), {}, {
display: "flex",
alignItems: "center",
gap: 16,
flexWrap: "wrap",
borderLeft: "3px solid ".concat(T.amber)
})
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Date"), /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontSize: 13
}
}, fd(tx.date))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Amount"), /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 800,
fontSize: 20,
color: T.emerald
}
}, $$(tx.amount))), tx.fee > 0 && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Fee"), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 12,
color: T.muted
}
}, "\u2212", $$(tx.fee))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Source"), /*#__PURE__*/React.createElement("span", {
style: S.tag(T.sky)
}, tx.src)), /*#__PURE__*/React.createElement("div", {
style: {
flex: 1,
minWidth: 100
}
}, /*#__PURE__*/React.createElement("div", {
style: S.lbl
}, "Description"), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 13
}
}, tx.desc)), /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setCatTx(tx);
},
style: S.btn(T.amber)
}, "Categorize \u2192"));
}))), tab === "txns" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
marginBottom: 14,
flexWrap: "wrap",
alignItems: "center"
}
}, /*#__PURE__*/React.createElement("input", {
placeholder: "Search\u2026",
value: txQ,
onChange: function onChange(e) {
return setTxQ(e.target.value);
},
style: _objectSpread(_objectSpread({}, S.inp), {}, {
width: 200,
padding: "7px 12px"
})
}), /*#__PURE__*/React.createElement("select", {
value: txF,
onChange: function onChange(e) {
return setTxF(e.target.value);
},
style: _objectSpread(_objectSpread({}, S.inp), {}, {
width: "auto",
padding: "7px 12px"
})
}, ["All", "inbox", "categorized"].map(function (s) {
return /*#__PURE__*/React.createElement("option", {
key: s
}, s);
})), /*#__PURE__*/React.createElement("select", {
value: txBU,
onChange: function onChange(e) {
return setTxBU(e.target.value);
},
style: _objectSpread(_objectSpread({}, S.inp), {}, {
width: "auto",
padding: "7px 12px"
})
}, ["All"].concat(BUS).map(function (b) {
return /*#__PURE__*/React.createElement("option", {
key: b,
value: b
}, b === "All" ? "All BUs" : BUL[b]);
})), /*#__PURE__*/React.createElement("div", {
style: {
marginLeft: "auto",
color: T.muted,
fontSize: 12,
fontFamily: "'DM Mono',monospace"
}
}, filtTx.length, " \xB7 ", $(filtTx.reduce(function (s, t) {
return s + t.amount;
}, 0)))), /*#__PURE__*/React.createElement("div", {
style: _objectSpread(_objectSpread({}, S.card), {}, {
padding: 0,
overflow: "hidden"
})
}, /*#__PURE__*/React.createElement("div", {
style: {
overflowX: "auto"
}
}, /*#__PURE__*/React.createElement("table", {
style: {
width: "100%",
borderCollapse: "collapse",
fontSize: 13
}
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", {
style: {
background: T.surface
}
}, /*#__PURE__*/React.createElement(TH, {
c: "Date"
}), /*#__PURE__*/React.createElement(TH, {
c: "Client"
}), /*#__PURE__*/React.createElement(TH, {
c: "Desc"
}), /*#__PURE__*/React.createElement(TH, {
c: "Amount"
}), /*#__PURE__*/React.createElement(TH, {
c: "BU"
}), /*#__PURE__*/React.createElement(TH, {
c: "Type"
}), /*#__PURE__*/React.createElement(TH, {
c: "Cat"
}), /*#__PURE__*/React.createElement(TH, {
c: "Source"
}), /*#__PURE__*/React.createElement(TH, {
c: "Status"
}), /*#__PURE__*/React.createElement(TH, {
c: ""
}))), /*#__PURE__*/React.createElement("tbody", null, filtTx.map(function (tx, i) {
return /*#__PURE__*/React.createElement("tr", {
key: tx.id,
className: "rh",
style: {
background: i % 2 === 0 ? T.card : T.card + "88"
}
}, /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontSize: 12,
color: T.muted
}
}, fd(tx.date))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontWeight: 600
}
}, cn(tx.cId))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontSize: 12
}
}, tx.desc)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
color: T.emerald
}
}, $$(tx.amount))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(BUTag, {
bu: tx.bu
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(TTag, {
type: tx.type
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontSize: 12
}
}, tx.cat || "—")), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: S.tag(T.sky)
}, tx.src)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(Dot, {
s: tx.st
})), /*#__PURE__*/React.createElement(TD, null, tx.st === "inbox" && /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setCatTx(tx);
},
style: _objectSpread(_objectSpread({}, S.btn(T.amber + "22", T.amber)), {}, {
padding: "4px 10px",
fontSize: 11,
border: "1px solid ".concat(T.amber, "33")
})
}, "Categorize")));
})))))), tab === "plans" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(SH, {
title: "Plans \u2014 ".concat(plans.length),
action: /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowPlan(true);
},
style: S.btn(T.emerald)
}, "+ Add Plan")
}), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
flexDirection: "column",
gap: 14
}
}, plans.map(function (plan) {
var client = clients.find(function (c) {
return c.id === plan.clientId;
});
var rcv = plan.payments.filter(function (sp) {
return sp.status === "received";
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0);
var total = plan.payments.reduce(function (s, sp) {
return s + sp.amount;
}, 0);
return /*#__PURE__*/React.createElement("div", {
key: plan.id,
style: S.card
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
marginBottom: 12,
flexWrap: "wrap",
gap: 8
}
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 8,
alignItems: "center",
marginBottom: 4,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement("span", {
style: {
fontWeight: 800,
fontSize: 14,
fontFamily: "'Syne',sans-serif"
}
}, plan.label), /*#__PURE__*/React.createElement(BUTag, {
bu: plan.bu
}), /*#__PURE__*/React.createElement(TTag, {
type: plan.type
})), /*#__PURE__*/React.createElement("div", {
style: {
color: T.muted,
fontSize: 12
}
}, (client === null || client === void 0 ? void 0 : client.name) || "—", " \xB7 ", plan.category)), /*#__PURE__*/React.createElement("div", {
style: {
textAlign: "right"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontSize: 15,
fontWeight: 700
}
}, $(rcv), " ", /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontWeight: 400
}
}, "/ ", $(total))), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.muted
}
}, plan.payments.filter(function (sp) {
return sp.status === "received";
}).length, "/", plan.payments.length, " received"))), /*#__PURE__*/React.createElement("div", {
style: {
height: 4,
background: T.border,
borderRadius: 2,
marginBottom: 12
}
}, /*#__PURE__*/React.createElement("div", {
style: {
height: "100%",
width: "".concat(total > 0 ? rcv / total * 100 : 0, "%"),
background: T[plan.bu] || T.emerald,
borderRadius: 2
}
})), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 8,
flexWrap: "wrap"
}
}, plan.payments.map(function (sp) {
return /*#__PURE__*/React.createElement("div", {
key: sp.id,
style: {
background: sp.status === "received" ? T.emerald + "18" : T.surface,
border: "1px solid ".concat(sp.status === "received" ? T.emerald + "44" : T.border),
borderRadius: 8,
padding: "8px 12px",
minWidth: 105
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 10,
color: T.muted,
marginBottom: 3
}
}, fd(sp.dueDate), sp.isBalance ? " · bal" : ""), /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
fontSize: 14,
color: sp.status === "received" ? T.emerald : T.text
}
}, $$(sp.amount)), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 10,
marginTop: 3
}
}, /*#__PURE__*/React.createElement(Dot, {
s: sp.status
})), sp.status === "scheduled" && /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return markRcv(plan.id, sp.id);
},
style: _objectSpread(_objectSpread({}, S.btn(T.emerald + "22", T.emerald)), {}, {
padding: "2px 8px",
fontSize: 10,
border: "1px solid ".concat(T.emerald, "33"),
marginTop: 4,
width: "100%"
})
}, "\u2713"));
})));
}))), tab === "clients" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(SH, {
title: "Clients \u2014 ".concat(clients.length)
}), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "repeat(auto-fill,minmax(270px,1fr))",
gap: 14
}
}, clients.map(function (c) {
var ct = done.filter(function (t) {
return t.cId === c.id;
});
var cp = plans.filter(function (p) {
return p.clientId === c.id;
});
var paid = ct.reduce(function (s, t) {
return s + t.amount;
}, 0);
var exp = cp.flatMap(function (p) {
return p.payments;
}).filter(function (sp) {
return sp.status === "scheduled";
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0);
return /*#__PURE__*/React.createElement("div", {
key: c.id,
style: S.card
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
marginBottom: 10
}
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
fontWeight: 800,
fontSize: 14,
marginBottom: 3,
fontFamily: "'Syne',sans-serif"
}
}, c.name), /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 11,
color: T.dim,
fontFamily: "'DM Mono',monospace"
}
}, c.id)), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 4,
flexWrap: "wrap"
}
}, c.bus.map(function (b) {
return /*#__PURE__*/React.createElement(BUTag, {
key: b,
bu: b
});
}))), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gap: 8,
marginTop: 8
}
}, [["Paid", $(paid), T.emerald], ["Expected", $(exp), T.amber], ["Plans", cp.length, T.text]].map(function (_ref16) {
var _ref17 = _slicedToArray(_ref16, 3),
l = _ref17[0],
v = _ref17[1],
col = _ref17[2];
return /*#__PURE__*/React.createElement("div", {
key: l,
style: {
background: T.surface,
borderRadius: 8,
padding: "8px 10px"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontSize: 10,
color: T.muted,
marginBottom: 3
}
}, l), /*#__PURE__*/React.createElement("div", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
fontSize: 13,
color: col
}
}, v));
})), cp.length > 0 && /*#__PURE__*/React.createElement("div", {
style: {
marginTop: 8
}
}, cp.map(function (p) {
return /*#__PURE__*/React.createElement("div", {
key: p.id,
style: {
fontSize: 11,
color: T.muted,
padding: "3px 0",
borderTop: "1px solid ".concat(T.border),
display: "flex",
gap: 6,
alignItems: "center"
}
}, /*#__PURE__*/React.createElement("span", {
style: {
flex: 1
}
}, p.label), /*#__PURE__*/React.createElement(TTag, {
type: p.type
}));
})));
}))), tab === "reports" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
marginBottom: 16,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement("select", {
value: rBU,
onChange: function onChange(e) {
return setRBU(e.target.value);
},
style: _objectSpread(_objectSpread({}, S.inp), {}, {
width: "auto",
padding: "7px 12px"
})
}, ["All"].concat(BUS).map(function (b) {
return /*#__PURE__*/React.createElement("option", {
key: b,
value: b
}, b === "All" ? "All BUs" : BUL[b]);
})), /*#__PURE__*/React.createElement("select", {
value: rType,
onChange: function onChange(e) {
return setRType(e.target.value);
},
style: _objectSpread(_objectSpread({}, S.inp), {}, {
width: "auto",
padding: "7px 12px"
})
}, /*#__PURE__*/React.createElement("option", {
value: "All"
}, "All Types"), PTYPES.map(function (t) {
return /*#__PURE__*/React.createElement("option", {
key: t,
value: t
}, PLBL[t]);
}))), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: 14,
marginBottom: 14
}
}, /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: "Active Plans"
}), /*#__PURE__*/React.createElement("table", {
style: {
width: "100%",
borderCollapse: "collapse"
}
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement(TH, {
c: "Client"
}), /*#__PURE__*/React.createElement(TH, {
c: "BU"
}), /*#__PURE__*/React.createElement(TH, {
c: "Type"
}), /*#__PURE__*/React.createElement(TH, {
c: "Value"
}))), /*#__PURE__*/React.createElement("tbody", null, plans.filter(function (p) {
return (rBU === "All" || p.bu === rBU) && (rType === "All" || p.type === rType);
}).map(function (p) {
return /*#__PURE__*/React.createElement("tr", {
key: p.id,
className: "rh"
}, /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("div", {
style: {
fontWeight: 600,
fontSize: 13
}
}, cn(p.clientId)), /*#__PURE__*/React.createElement("div", {
style: {
color: T.muted,
fontSize: 11
}
}, p.label)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(BUTag, {
bu: p.bu
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement(TTag, {
type: p.type
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
color: T.emerald
}
}, $(p.payments.reduce(function (s, sp) {
return s + sp.amount;
}, 0)))));
})))), /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: "Revenue by Category"
}), CATS.map(function (cat) {
var total = done.filter(function (t) {
return t.cat === cat && (rBU === "All" || t.bu === rBU);
}).reduce(function (s, t) {
return s + t.amount;
}, 0);
if (!total) return null;
var max = Math.max.apply(Math, _toConsumableArray(CATS.map(function (c) {
return done.filter(function (t) {
return t.cat === c && (rBU === "All" || t.bu === rBU);
}).reduce(function (s, t) {
return s + t.amount;
}, 0);
})).concat([1]));
return /*#__PURE__*/React.createElement("div", {
key: cat,
style: {
marginBottom: 10
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
marginBottom: 3
}
}, /*#__PURE__*/React.createElement("span", {
style: {
fontSize: 12
}
}, cat), /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontSize: 12,
color: T.muted
}
}, $(total))), /*#__PURE__*/React.createElement("div", {
style: {
height: 4,
background: T.border,
borderRadius: 2
}
}, /*#__PURE__*/React.createElement("div", {
style: {
height: "100%",
width: "".concat(total / max * 100, "%"),
background: T.sky,
borderRadius: 2
}
})));
}))), /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement(SH, {
title: "Client Summary"
}), /*#__PURE__*/React.createElement("div", {
style: {
overflowX: "auto"
}
}, /*#__PURE__*/React.createElement("table", {
style: {
width: "100%",
borderCollapse: "collapse"
}
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement(TH, {
c: "Client"
}), /*#__PURE__*/React.createElement(TH, {
c: "ID"
}), /*#__PURE__*/React.createElement(TH, {
c: "BU"
}), /*#__PURE__*/React.createElement(TH, {
c: "Paid"
}), /*#__PURE__*/React.createElement(TH, {
c: "Expected"
}), /*#__PURE__*/React.createElement(TH, {
c: "Plans"
}), /*#__PURE__*/React.createElement(TH, {
c: "Categories"
}))), /*#__PURE__*/React.createElement("tbody", null, clients.filter(function (c) {
return rBU === "All" || c.bus.includes(rBU);
}).map(function (c) {
var ct = done.filter(function (t) {
return t.cId === c.id;
});
var cp = plans.filter(function (p) {
return p.clientId === c.id;
});
var paid = ct.reduce(function (s, t) {
return s + t.amount;
}, 0);
var exp = cp.flatMap(function (p) {
return p.payments;
}).filter(function (sp) {
return sp.status === "scheduled";
}).reduce(function (s, sp) {
return s + sp.amount;
}, 0);
var cats = _toConsumableArray(new Set(ct.map(function (t) {
return t.cat;
}).filter(Boolean)));
return /*#__PURE__*/React.createElement("tr", {
key: c.id,
className: "rh"
}, /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontWeight: 700
}
}, c.name)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontSize: 11,
color: T.dim
}
}, c.id)), /*#__PURE__*/React.createElement(TD, null, c.bus.map(function (b) {
return /*#__PURE__*/React.createElement(BUTag, {
key: b,
bu: b
});
})), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
color: T.emerald,
fontWeight: 700
}
}, $(paid))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
color: T.amber
}
}, exp > 0 ? $(exp) : "—")), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted
}
}, cp.length)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 4,
flexWrap: "wrap"
}
}, cats.map(function (cat) {
return /*#__PURE__*/React.createElement("span", {
key: cat,
style: S.tag(T.sky)
}, cat);
}))));
})))))), tab === "expenses" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
marginBottom: 14,
flexWrap: "wrap",
gap: 10
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
flexWrap: "wrap"
}
}, /*#__PURE__*/React.createElement(KPI, {
label: "Monthly",
value: $(totExp),
color: T.rose,
icon: "\u2193"
}), /*#__PURE__*/React.createElement(KPI, {
label: "Annual",
value: $(totExp * 12),
color: T.rose
}), /*#__PURE__*/React.createElement(KPI, {
label: "Ratio",
value: compMTD ? (totExp / compMTD * 100).toFixed(0) + "%" : "—",
color: T.orange,
sub: "vs confirmed"
})), /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowAddExp(true);
},
style: S.btn(T.rose, "#fff")
}, "+ Add Expense")), /*#__PURE__*/React.createElement("div", {
style: _objectSpread(_objectSpread({}, S.card), {}, {
padding: 0,
overflow: "hidden"
})
}, /*#__PURE__*/React.createElement("table", {
style: {
width: "100%",
borderCollapse: "collapse"
}
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", {
style: {
background: T.surface
}
}, /*#__PURE__*/React.createElement(TH, {
c: "Name"
}), /*#__PURE__*/React.createElement(TH, {
c: "Amount"
}), /*#__PURE__*/React.createElement(TH, {
c: "Category"
}), /*#__PURE__*/React.createElement(TH, {
c: "Freq"
}), /*#__PURE__*/React.createElement(TH, {
c: "Vendor"
}), /*#__PURE__*/React.createElement(TH, {
c: ""
}))), /*#__PURE__*/React.createElement("tbody", null, exps.map(function (e, i) {
return /*#__PURE__*/React.createElement("tr", {
key: e.id,
className: "rh",
style: {
background: i % 2 === 0 ? T.card : T.card + "88"
}
}, /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontWeight: 600
}
}, e.name)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
fontFamily: "'DM Mono',monospace",
fontWeight: 700,
color: T.rose
}
}, $$(e.amount))), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontSize: 12
}
}, e.cat)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: S.tag(T.sky)
}, e.freq)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
fontSize: 12
}
}, e.vendor)), /*#__PURE__*/React.createElement(TD, null, /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setExps(function (prev) {
return prev.filter(function (x) {
return x.id !== e.id;
});
});
},
style: _objectSpread(_objectSpread({}, S.btn(T.rose + "22", T.rose)), {}, {
padding: "4px 10px",
fontSize: 11,
border: "1px solid ".concat(T.rose, "33")
})
}, "Remove")));
})), /*#__PURE__*/React.createElement("tfoot", null, /*#__PURE__*/React.createElement("tr", {
style: {
background: T.surface,
borderTop: "2px solid ".concat(T.border2)
}
}, /*#__PURE__*/React.createElement("td", {
style: {
padding: "12px 14px",
fontWeight: 800,
color: T.text,
fontFamily: "'Syne',sans-serif"
}
}, "TOTAL"), /*#__PURE__*/React.createElement("td", {
style: {
padding: "12px 14px",
fontFamily: "'DM Mono',monospace",
fontWeight: 800,
color: T.rose,
fontSize: 15
}
}, $(totExp), "/mo"), /*#__PURE__*/React.createElement("td", {
colSpan: 4,
style: {
padding: "12px 14px",
color: T.muted,
fontSize: 12
}
}, $(totExp * 12), "/year")))))), tab === "sources" && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(SH, {
title: "Data Sources",
action: syncLog.length > 0 && /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowLog(true);
},
style: S.ghost
}, "Sync Log (", syncLog.length, ")")
}), /*#__PURE__*/React.createElement("div", {
style: _objectSpread(_objectSpread({}, S.card), {}, {
marginBottom: 14
})
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
justifyContent: "space-between",
marginBottom: 14,
alignItems: "center"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
fontWeight: 800,
fontSize: 14,
fontFamily: "'Syne',sans-serif",
color: T.sky
}
}, "\u25B2 Stripe Accounts"), /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setStripeA(function (prev) {
return [].concat(_toConsumableArray(prev), [{
id: "sa-".concat(Date.now()),
label: "New Account",
key: "",
lastSync: null,
status: "idle"
}]);
});
},
style: S.ghost
}, "+ Add Account")), /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderRadius: 8,
padding: "10px 14px",
marginBottom: 12,
fontSize: 12,
color: T.muted,
borderLeft: "3px solid ".concat(T.sky)
}
}, /*#__PURE__*/React.createElement("strong", {
style: {
color: T.text
}
}, "Get key:"), " Stripe Dashboard \u2192 Developers \u2192 API keys \u2192 ", /*#__PURE__*/React.createElement("code", {
style: {
color: T.sky
}
}, "sk_live_\u2026"), ". Use a Restricted Key with read-only Balance + Charges."), stripeA.map(function (a) {
var sc = {
idle: T.muted,
syncing: T.amber,
ok: T.emerald,
error: T.rose
}[a.status];
return /*#__PURE__*/React.createElement("div", {
key: a.id,
style: {
background: T.surface,
borderRadius: 10,
padding: 14,
marginBottom: 10,
border: "1px solid ".concat(T.border2)
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 12,
flexWrap: "wrap",
alignItems: "flex-end"
}
}, /*#__PURE__*/React.createElement("div", {
style: {
flex: "0 0 190px"
}
}, /*#__PURE__*/React.createElement("label", {
style: S.lbl
}, "Name"), /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: a.label,
onChange: function onChange(e) {
return setStripeA(function (p) {
return p.map(function (x) {
return x.id === a.id ? _objectSpread(_objectSpread({}, x), {}, {
label: e.target.value
}) : x;
});
});
}
})), /*#__PURE__*/React.createElement("div", {
style: {
flex: 1,
minWidth: 200
}
}, /*#__PURE__*/React.createElement("label", {
style: S.lbl
}, "Secret Key ", /*#__PURE__*/React.createElement("span", {
style: {
color: T.rose,
fontSize: 10,
fontWeight: 400
}
}, "memory only")), /*#__PURE__*/React.createElement("input", {
style: _objectSpread(_objectSpread({}, S.inp), {}, {
fontFamily: "'DM Mono',monospace",
fontSize: 12
}),
type: "password",
value: a.key,
placeholder: "sk_live_\u2026",
onChange: function onChange(e) {
return setStripeA(function (p) {
return p.map(function (x) {
return x.id === a.id ? _objectSpread(_objectSpread({}, x), {}, {
key: e.target.value,
status: "idle"
}) : x;
});
});
}
})), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 6
}
}, /*#__PURE__*/React.createElement("button", {
style: S.btn(T.sky, "#000")
}, "\u27F3 Sync"), /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setStripeA(function (p) {
return p.filter(function (x) {
return x.id !== a.id;
});
});
},
style: _objectSpread(_objectSpread({}, S.btn(T.rose + "22", T.rose)), {}, {
border: "1px solid ".concat(T.rose, "33")
})
}, "\u2715"))), /*#__PURE__*/React.createElement("div", {
style: {
marginTop: 8,
fontSize: 11,
color: sc
}
}, "\u25CF ", a.status));
})), /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: 14
}
}, /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement("div", {
style: {
fontWeight: 800,
fontSize: 14,
fontFamily: "'Syne',sans-serif",
color: T.orange,
marginBottom: 8
}
}, "\u25C6 Sawyer"), /*#__PURE__*/React.createElement("p", {
style: {
color: T.muted,
fontSize: 13,
margin: "0 0 10px"
}
}, "Uses their own Stripe platform. Use Zapier or manual entry."), /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderRadius: 8,
padding: "10px 14px",
fontSize: 12,
color: T.muted,
borderLeft: "3px solid ".concat(T.orange)
}
}, /*#__PURE__*/React.createElement("strong", {
style: {
color: T.text
}
}, "Zapier:"), " Sawyer \u2192 New Order \u2192 Google Sheets Append Row.")), /*#__PURE__*/React.createElement("div", {
style: S.card
}, /*#__PURE__*/React.createElement("div", {
style: {
fontWeight: 800,
fontSize: 14,
fontFamily: "'Syne',sans-serif",
color: T.emerald,
marginBottom: 8
}
}, "\u25C6 Zelle + Manual"), /*#__PURE__*/React.createElement("p", {
style: {
color: T.muted,
fontSize: 13,
margin: "0 0 10px"
}
}, "No API. Use Manual Tx \u2014 lands in inbox ready to categorize."), /*#__PURE__*/React.createElement("div", {
style: {
background: T.surface,
borderRadius: 8,
padding: "10px 14px",
fontSize: 12,
color: T.muted,
borderLeft: "3px solid ".concat(T.emerald)
}
}, /*#__PURE__*/React.createElement("strong", {
style: {
color: T.text
}
}, "Tip:"), " Bank CSV export often includes Zelle payments."))))), catTx && /*#__PURE__*/React.createElement(CatModal, {
tx: catTx,
clients: clients,
plans: plans,
onSave: saveCat,
onClose: function onClose() {
return setCatTx(null);
}
}), showPlan && /*#__PURE__*/React.createElement(PlanModal, {
clients: clients,
onSave: addPlan,
onClose: function onClose() {
return setShowPlan(false);
}
}), showAddTx && /*#__PURE__*/React.createElement(Modal, {
title: "Add Manual Transaction",
onClose: function onClose() {
return setShowAddTx(false);
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0 16px"
}
}, /*#__PURE__*/React.createElement(FF, {
label: "Date"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "date",
value: nTx.date,
onChange: function onChange(e) {
return setNTx(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
date: e.target.value
});
});
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Amount ($)"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: nTx.amount,
onChange: function onChange(e) {
return setNTx(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
amount: e.target.value
});
});
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Source"
}, /*#__PURE__*/React.createElement(FS, {
value: nTx.src,
onChange: function onChange(v) {
return setNTx(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
src: v
});
});
},
options: SRCS
})), /*#__PURE__*/React.createElement(FF, {
label: "Description"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: nTx.desc,
onChange: function onChange(e) {
return setNTx(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
desc: e.target.value
});
});
},
placeholder: "What is this payment?"
}))), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
justifyContent: "flex-end",
marginTop: 8
}
}, /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowAddTx(false);
},
style: S.ghost
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
onClick: addTx,
style: S.btn(T.amber)
}, "Add to Inbox"))), showAddExp && /*#__PURE__*/React.createElement(Modal, {
title: "Add Expense",
onClose: function onClose() {
return setShowAddExp(false);
}
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "grid",
gridTemplateColumns: "1fr 1fr",
gap: "0 16px"
}
}, /*#__PURE__*/React.createElement(FF, {
label: "Name"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: nExp.name,
onChange: function onChange(e) {
return setNExp(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
name: e.target.value
});
});
},
placeholder: "e.g. Stripe Fees"
})), /*#__PURE__*/React.createElement(FF, {
label: "Amount ($)"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
type: "number",
value: nExp.amount,
onChange: function onChange(e) {
return setNExp(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
amount: e.target.value
});
});
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Category"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: nExp.cat,
onChange: function onChange(e) {
return setNExp(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
cat: e.target.value
});
});
}
})), /*#__PURE__*/React.createElement(FF, {
label: "Frequency"
}, /*#__PURE__*/React.createElement(FS, {
value: nExp.freq,
onChange: function onChange(v) {
return setNExp(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
freq: v
});
});
},
options: ["Monthly", "One-time", "Annual", "Weekly"]
})), /*#__PURE__*/React.createElement(FF, {
label: "Vendor"
}, /*#__PURE__*/React.createElement("input", {
style: S.inp,
value: nExp.vendor,
onChange: function onChange(e) {
return setNExp(function (p) {
return _objectSpread(_objectSpread({}, p), {}, {
vendor: e.target.value
});
});
}
}))), /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
gap: 10,
justifyContent: "flex-end",
marginTop: 8
}
}, /*#__PURE__*/React.createElement("button", {
onClick: function onClick() {
return setShowAddExp(false);
},
style: S.ghost
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
onClick: addExp,
style: S.btn(T.rose, "#fff")
}, "Add Expense"))), showLog && /*#__PURE__*/React.createElement(Modal, {
title: "Sync Log",
onClose: function onClose() {
return setShowLog(false);
},
width: 620
}, /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
flexDirection: "column",
gap: 6,
maxHeight: 380,
overflowY: "auto"
}
}, syncLog.map(function (e, i) {
return /*#__PURE__*/React.createElement("div", {
key: i,
style: {
display: "flex",
gap: 10,
fontSize: 12,
padding: "6px 10px",
background: T.surface,
borderRadius: 6,
borderLeft: "3px solid ".concat(e.ok ? T.emerald : T.rose)
}
}, /*#__PURE__*/React.createElement("span", {
style: {
color: T.muted,
flexShrink: 0
}
}, e.ts), /*#__PURE__*/React.createElement("span", {
style: {
color: T.sky,
flexShrink: 0,
fontWeight: 700
}
}, "[", e.acct, "]"), /*#__PURE__*/React.createElement("span", {
style: {
color: e.ok ? T.text : T.rose
}
}, e.msg));
}))));
}
ReactDOM.createRoot(document.getElementById("root")).render(/*#__PURE__*/React.createElement(App, null));
ReactDOM.createRoot(document.getElementById('root')).render(React.createElement(App,null));