@burdenoff/microfe-proserviceworld 2026.1026.1 → 2026.1028.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +37 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js +112 -72
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +193 -121
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.js +331 -161
- package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,166 +1,336 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cn as
|
|
3
|
-
import { Banner as
|
|
4
|
-
import { useAnalytics as
|
|
5
|
-
import { useDeferredValue as
|
|
6
|
-
import { AlertCircle as
|
|
7
|
-
import { Fragment as
|
|
8
|
-
import { Button as
|
|
1
|
+
import { useCancelInvoice as e, useClients as t, useCreateInvoice as n, useEngagements as r, useInvoice as i, useInvoices as a, useMarkInvoicePaid as o, useSendInvoice as s } from "../hooks/useProServiceWorldApi.js";
|
|
2
|
+
import { cn as c } from "../utils/cn.js";
|
|
3
|
+
import { Banner as l, Empty as u, ErrorState as d, Field as f, LoadingBlock as p, MetricCard as m, Modal as h, NativeSelect as g, PageHeader as _, SectionCard as v, StatusPill as y, TableWrap as b, Td as x, TextArea as S, TextInput as C, Th as w, enumOptions as T, fmtDate as E, fmtMoney as D } from "../components/ui.js";
|
|
4
|
+
import { useAnalytics as O } from "../hooks/useAnalytics.js";
|
|
5
|
+
import { useDeferredValue as ee, useMemo as te, useState as k } from "react";
|
|
6
|
+
import { AlertCircle as ne, CheckCircle2 as re, Eye as ie, Plus as A, Receipt as j, Search as M, Send as N, Wallet as P, XCircle as F } from "lucide-react";
|
|
7
|
+
import { Fragment as I, jsx as L, jsxs as R } from "react/jsx-runtime";
|
|
8
|
+
import { Button as z } from "@burdenoff/fe-libs/ui";
|
|
9
9
|
//#region src/proserviceworld/pages/InvoicesPage.tsx
|
|
10
|
-
var
|
|
10
|
+
var B = [
|
|
11
11
|
"DRAFT",
|
|
12
12
|
"SENT",
|
|
13
13
|
"PAID",
|
|
14
14
|
"OVERDUE",
|
|
15
15
|
"CANCELLED"
|
|
16
|
-
],
|
|
17
|
-
let [
|
|
18
|
-
status:
|
|
19
|
-
search:
|
|
20
|
-
}), { emitFact:
|
|
21
|
-
return /* @__PURE__ */
|
|
16
|
+
], V = () => {
|
|
17
|
+
let [n, r] = k(""), [i, f] = k(""), h = ee(i), [S, I] = k(!1), [V, H] = k(null), [U, W] = k(null), { data: G, isLoading: se, error: K, refetch: ce } = a({
|
|
18
|
+
status: n || void 0,
|
|
19
|
+
search: h.trim() || void 0
|
|
20
|
+
}), { emitFact: le } = O(), q = s(), J = o(), Y = e(), X = t({ pagination: { limit: 100 } }), Z = te(() => new Map((X.data?.items ?? []).map((e) => [e.id, e.name])), [X.data]), Q = (G?.items ?? []).filter((e) => e.status === "SENT" || e.status === "OVERDUE"), $ = (G?.items ?? []).filter((e) => e.status === "PAID"), ue = Q.reduce((e, t) => e + t.total, 0), de = $.reduce((e, t) => e + t.total, 0);
|
|
21
|
+
return /* @__PURE__ */ R("div", {
|
|
22
22
|
className: "space-y-6",
|
|
23
23
|
children: [
|
|
24
|
-
/* @__PURE__ */
|
|
24
|
+
/* @__PURE__ */ L(_, {
|
|
25
25
|
title: "Invoices",
|
|
26
26
|
subtitle: "Assemble invoices from time, milestones and fixed-fee schedules — and track what's outstanding.",
|
|
27
|
-
icon: /* @__PURE__ */
|
|
28
|
-
actions: /* @__PURE__ */
|
|
29
|
-
onClick: () =>
|
|
30
|
-
children: [/* @__PURE__ */
|
|
27
|
+
icon: /* @__PURE__ */ L(j, { className: "h-6 w-6" }),
|
|
28
|
+
actions: /* @__PURE__ */ R(z, {
|
|
29
|
+
onClick: () => I(!0),
|
|
30
|
+
children: [/* @__PURE__ */ L(A, { className: "mr-1.5 h-4 w-4" }), "New invoice"]
|
|
31
31
|
})
|
|
32
32
|
}),
|
|
33
|
-
|
|
34
|
-
tone:
|
|
35
|
-
onClose: () =>
|
|
36
|
-
children:
|
|
33
|
+
U && /* @__PURE__ */ L(l, {
|
|
34
|
+
tone: U.tone,
|
|
35
|
+
onClose: () => W(null),
|
|
36
|
+
children: U.text
|
|
37
37
|
}),
|
|
38
|
-
/* @__PURE__ */
|
|
38
|
+
/* @__PURE__ */ R("div", {
|
|
39
39
|
className: "grid grid-cols-1 gap-3 sm:grid-cols-3",
|
|
40
40
|
children: [
|
|
41
|
-
/* @__PURE__ */
|
|
41
|
+
/* @__PURE__ */ L(m, {
|
|
42
42
|
label: "Invoices",
|
|
43
|
-
value:
|
|
44
|
-
icon: /* @__PURE__ */
|
|
43
|
+
value: G?.totalCount ?? 0,
|
|
44
|
+
icon: /* @__PURE__ */ L(j, { className: "h-4 w-4" })
|
|
45
45
|
}),
|
|
46
|
-
/* @__PURE__ */
|
|
46
|
+
/* @__PURE__ */ L(m, {
|
|
47
47
|
label: "Outstanding",
|
|
48
|
-
value:
|
|
48
|
+
value: D(ue),
|
|
49
49
|
hint: `${Q.length} sent + overdue`,
|
|
50
|
-
icon: /* @__PURE__ */
|
|
50
|
+
icon: /* @__PURE__ */ L(ne, { className: "h-4 w-4" }),
|
|
51
51
|
tone: "warning"
|
|
52
52
|
}),
|
|
53
|
-
/* @__PURE__ */
|
|
53
|
+
/* @__PURE__ */ L(m, {
|
|
54
54
|
label: "Collected",
|
|
55
|
-
value:
|
|
55
|
+
value: D(de),
|
|
56
56
|
hint: `${$.length} paid`,
|
|
57
|
-
icon: /* @__PURE__ */
|
|
57
|
+
icon: /* @__PURE__ */ L(P, { className: "h-4 w-4" }),
|
|
58
58
|
tone: "success"
|
|
59
59
|
})
|
|
60
60
|
]
|
|
61
61
|
}),
|
|
62
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ R("div", {
|
|
63
63
|
className: "flex flex-col gap-2 sm:flex-row sm:items-center",
|
|
64
|
-
children: [/* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ R("div", {
|
|
65
65
|
className: "relative flex-1",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
66
|
+
children: [/* @__PURE__ */ L(M, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary" }), /* @__PURE__ */ L(C, {
|
|
67
67
|
placeholder: "Search invoices…",
|
|
68
|
-
value:
|
|
68
|
+
value: i,
|
|
69
69
|
onChange: (e) => f(e.target.value),
|
|
70
70
|
onKeyDown: (e) => {
|
|
71
|
-
e.key === "Enter" &&
|
|
71
|
+
e.key === "Enter" && i.trim() && le("psw.search.performed", {
|
|
72
72
|
entityType: "invoice",
|
|
73
|
-
queryLength:
|
|
73
|
+
queryLength: i.trim().length
|
|
74
74
|
});
|
|
75
75
|
},
|
|
76
76
|
className: "pl-9"
|
|
77
77
|
})]
|
|
78
|
-
}), /* @__PURE__ */
|
|
79
|
-
value:
|
|
80
|
-
onChange: (e) =>
|
|
78
|
+
}), /* @__PURE__ */ R(g, {
|
|
79
|
+
value: n,
|
|
80
|
+
onChange: (e) => r(e.target.value),
|
|
81
81
|
className: "sm:w-48",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
82
|
+
children: [/* @__PURE__ */ L("option", {
|
|
83
83
|
value: "",
|
|
84
84
|
children: "All statuses"
|
|
85
|
-
}),
|
|
85
|
+
}), T(B)]
|
|
86
86
|
})]
|
|
87
87
|
}),
|
|
88
|
-
|
|
88
|
+
se ? /* @__PURE__ */ L(p, {}) : K ? /* @__PURE__ */ L(d, {
|
|
89
89
|
error: K,
|
|
90
|
-
onRetry: () => void
|
|
91
|
-
}) : !
|
|
90
|
+
onRetry: () => void ce()
|
|
91
|
+
}) : !G || G.items.length === 0 ? /* @__PURE__ */ L(u, {
|
|
92
92
|
title: "No invoices yet",
|
|
93
93
|
description: "Raise an invoice for a client to start tracking receivables.",
|
|
94
|
-
icon: /* @__PURE__ */
|
|
95
|
-
action: /* @__PURE__ */
|
|
96
|
-
onClick: () =>
|
|
97
|
-
children: [/* @__PURE__ */
|
|
94
|
+
icon: /* @__PURE__ */ L(j, { className: "h-8 w-8" }),
|
|
95
|
+
action: /* @__PURE__ */ R(z, {
|
|
96
|
+
onClick: () => I(!0),
|
|
97
|
+
children: [/* @__PURE__ */ L(A, { className: "mr-1.5 h-4 w-4" }), "New invoice"]
|
|
98
98
|
})
|
|
99
|
-
}) : /* @__PURE__ */
|
|
99
|
+
}) : /* @__PURE__ */ L(v, {
|
|
100
100
|
title: "Invoices",
|
|
101
|
-
children: /* @__PURE__ */
|
|
102
|
-
/* @__PURE__ */
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
-
/* @__PURE__ */
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
/* @__PURE__ */
|
|
101
|
+
children: /* @__PURE__ */ R(b, { children: [/* @__PURE__ */ L("thead", { children: /* @__PURE__ */ R("tr", { children: [
|
|
102
|
+
/* @__PURE__ */ L(w, { children: "Number" }),
|
|
103
|
+
/* @__PURE__ */ L(w, { children: "Client" }),
|
|
104
|
+
/* @__PURE__ */ L(w, { children: "Total" }),
|
|
105
|
+
/* @__PURE__ */ L(w, { children: "Status" }),
|
|
106
|
+
/* @__PURE__ */ L(w, { children: "Due" }),
|
|
107
|
+
/* @__PURE__ */ L(w, {
|
|
108
108
|
className: "text-right",
|
|
109
109
|
children: "Actions"
|
|
110
110
|
})
|
|
111
|
-
] }) }), /* @__PURE__ */
|
|
111
|
+
] }) }), /* @__PURE__ */ L("tbody", { children: G.items.map((e) => /* @__PURE__ */ R("tr", {
|
|
112
112
|
className: "transition-colors hover:bg-bg-sunken/60",
|
|
113
113
|
children: [
|
|
114
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ L(x, { children: /* @__PURE__ */ L("span", {
|
|
115
115
|
className: "font-medium text-text-primary",
|
|
116
116
|
children: e.number
|
|
117
117
|
}) }),
|
|
118
|
-
/* @__PURE__ */
|
|
118
|
+
/* @__PURE__ */ L(x, {
|
|
119
119
|
className: "text-text-primary",
|
|
120
120
|
children: Z.get(e.clientId) ?? "—"
|
|
121
121
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ L(x, {
|
|
123
123
|
className: "whitespace-nowrap font-semibold text-text-primary",
|
|
124
|
-
children:
|
|
124
|
+
children: D(e.total, e.currency)
|
|
125
125
|
}),
|
|
126
|
-
/* @__PURE__ */
|
|
127
|
-
/* @__PURE__ */
|
|
128
|
-
className:
|
|
129
|
-
children:
|
|
126
|
+
/* @__PURE__ */ L(x, { children: /* @__PURE__ */ L(y, { status: e.status }) }),
|
|
127
|
+
/* @__PURE__ */ L(x, {
|
|
128
|
+
className: c("whitespace-nowrap", e.status === "OVERDUE" && "font-medium text-status-error-text"),
|
|
129
|
+
children: E(e.dueDate)
|
|
130
130
|
}),
|
|
131
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ L(x, {
|
|
132
132
|
className: "text-right",
|
|
133
|
-
children:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
133
|
+
children: /* @__PURE__ */ R("div", {
|
|
134
|
+
className: "flex items-center justify-end gap-1",
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ R(z, {
|
|
137
|
+
variant: "ghost",
|
|
138
|
+
size: "sm",
|
|
139
|
+
onClick: () => H(e.id),
|
|
140
|
+
children: [/* @__PURE__ */ L(ie, { className: "mr-1 h-4 w-4" }), "View"]
|
|
141
141
|
}),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
e.status === "DRAFT" && /* @__PURE__ */ R(z, {
|
|
143
|
+
variant: "ghost",
|
|
144
|
+
size: "sm",
|
|
145
|
+
disabled: q.isPending,
|
|
146
|
+
onClick: () => q.mutate(e.id, {
|
|
147
|
+
onSuccess: () => W({
|
|
148
|
+
tone: "success",
|
|
149
|
+
text: `${e.number} sent.`
|
|
150
|
+
}),
|
|
151
|
+
onError: (e) => W({
|
|
152
|
+
tone: "danger",
|
|
153
|
+
text: e instanceof Error ? e.message : "Failed."
|
|
154
|
+
})
|
|
155
|
+
}),
|
|
156
|
+
children: [/* @__PURE__ */ L(N, { className: "mr-1 h-4 w-4" }), "Send"]
|
|
157
|
+
}),
|
|
158
|
+
(e.status === "SENT" || e.status === "OVERDUE") && /* @__PURE__ */ R(z, {
|
|
159
|
+
variant: "ghost",
|
|
160
|
+
size: "sm",
|
|
161
|
+
disabled: J.isPending,
|
|
162
|
+
onClick: () => J.mutate(e.id, {
|
|
163
|
+
onSuccess: () => W({
|
|
164
|
+
tone: "success",
|
|
165
|
+
text: `${e.number} marked paid.`
|
|
166
|
+
}),
|
|
167
|
+
onError: (e) => W({
|
|
168
|
+
tone: "danger",
|
|
169
|
+
text: e instanceof Error ? e.message : "Failed."
|
|
170
|
+
})
|
|
171
|
+
}),
|
|
172
|
+
children: [/* @__PURE__ */ L(re, { className: "mr-1 h-4 w-4" }), "Mark paid"]
|
|
173
|
+
}),
|
|
174
|
+
(e.status === "DRAFT" || e.status === "SENT") && /* @__PURE__ */ R(z, {
|
|
175
|
+
variant: "ghost",
|
|
176
|
+
size: "sm",
|
|
177
|
+
disabled: Y.isPending,
|
|
178
|
+
onClick: () => Y.mutate(e.id, {
|
|
179
|
+
onSuccess: () => W({
|
|
180
|
+
tone: "success",
|
|
181
|
+
text: `${e.number} cancelled.`
|
|
182
|
+
}),
|
|
183
|
+
onError: (e) => W({
|
|
184
|
+
tone: "danger",
|
|
185
|
+
text: e instanceof Error ? e.message : "Failed."
|
|
186
|
+
})
|
|
187
|
+
}),
|
|
188
|
+
children: [/* @__PURE__ */ L(F, { className: "mr-1 h-4 w-4" }), "Cancel"]
|
|
145
189
|
})
|
|
146
|
-
|
|
147
|
-
children: [/* @__PURE__ */ I(A, { className: "mr-1 h-4 w-4" }), "Mark paid"]
|
|
190
|
+
]
|
|
148
191
|
})
|
|
149
192
|
})
|
|
150
193
|
]
|
|
151
194
|
}, e.id)) })] })
|
|
152
195
|
}),
|
|
153
|
-
|
|
154
|
-
onClose: () =>
|
|
155
|
-
onSaved: (e) =>
|
|
196
|
+
S && /* @__PURE__ */ L(oe, {
|
|
197
|
+
onClose: () => I(!1),
|
|
198
|
+
onSaved: (e) => W({
|
|
156
199
|
tone: "success",
|
|
157
200
|
text: `${e} created.`
|
|
158
201
|
})
|
|
202
|
+
}),
|
|
203
|
+
V && /* @__PURE__ */ L(ae, {
|
|
204
|
+
id: V,
|
|
205
|
+
clientName: Z,
|
|
206
|
+
onClose: () => H(null),
|
|
207
|
+
onCancelled: (e) => {
|
|
208
|
+
H(null), W({
|
|
209
|
+
tone: "success",
|
|
210
|
+
text: `${e} cancelled.`
|
|
211
|
+
});
|
|
212
|
+
}
|
|
159
213
|
})
|
|
160
214
|
]
|
|
161
215
|
});
|
|
162
|
-
},
|
|
163
|
-
let
|
|
216
|
+
}, ae = ({ id: t, clientName: n, onClose: r, onCancelled: a }) => {
|
|
217
|
+
let { data: o, isLoading: s, error: c } = i(t), f = e(), [m, g] = k(null);
|
|
218
|
+
return /* @__PURE__ */ L(h, {
|
|
219
|
+
open: !0,
|
|
220
|
+
onClose: r,
|
|
221
|
+
title: o ? `Invoice ${o.number}` : "Invoice",
|
|
222
|
+
footer: /* @__PURE__ */ R(I, { children: [/* @__PURE__ */ L(z, {
|
|
223
|
+
variant: "outline",
|
|
224
|
+
onClick: r,
|
|
225
|
+
children: "Close"
|
|
226
|
+
}), o && (o.status === "DRAFT" || o.status === "SENT") && /* @__PURE__ */ R(z, {
|
|
227
|
+
variant: "destructive",
|
|
228
|
+
disabled: f.isPending,
|
|
229
|
+
onClick: () => {
|
|
230
|
+
g(null), f.mutate(o.id, {
|
|
231
|
+
onSuccess: () => a(o.number),
|
|
232
|
+
onError: (e) => g(e instanceof Error ? e.message : "Failed.")
|
|
233
|
+
});
|
|
234
|
+
},
|
|
235
|
+
children: [/* @__PURE__ */ L(F, { className: "mr-1.5 h-4 w-4" }), f.isPending ? "Cancelling…" : "Cancel invoice"]
|
|
236
|
+
})] }),
|
|
237
|
+
children: /* @__PURE__ */ R("div", {
|
|
238
|
+
className: "space-y-3",
|
|
239
|
+
children: [m && /* @__PURE__ */ L(l, {
|
|
240
|
+
tone: "danger",
|
|
241
|
+
children: m
|
|
242
|
+
}), s ? /* @__PURE__ */ L(p, {}) : c ? /* @__PURE__ */ L(d, { error: c }) : o ? /* @__PURE__ */ R(I, { children: [
|
|
243
|
+
/* @__PURE__ */ R("div", {
|
|
244
|
+
className: "grid grid-cols-2 gap-3 text-sm",
|
|
245
|
+
children: [
|
|
246
|
+
/* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
247
|
+
className: "text-text-tertiary",
|
|
248
|
+
children: "Client"
|
|
249
|
+
}), /* @__PURE__ */ L("div", {
|
|
250
|
+
className: "font-medium text-text-primary",
|
|
251
|
+
children: n.get(o.clientId) ?? "—"
|
|
252
|
+
})] }),
|
|
253
|
+
/* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
254
|
+
className: "text-text-tertiary",
|
|
255
|
+
children: "Status"
|
|
256
|
+
}), /* @__PURE__ */ L(y, { status: o.status })] }),
|
|
257
|
+
/* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
258
|
+
className: "text-text-tertiary",
|
|
259
|
+
children: "Issue date"
|
|
260
|
+
}), /* @__PURE__ */ L("div", {
|
|
261
|
+
className: "text-text-primary",
|
|
262
|
+
children: E(o.issueDate)
|
|
263
|
+
})] }),
|
|
264
|
+
/* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
265
|
+
className: "text-text-tertiary",
|
|
266
|
+
children: "Due date"
|
|
267
|
+
}), /* @__PURE__ */ L("div", {
|
|
268
|
+
className: "text-text-primary",
|
|
269
|
+
children: E(o.dueDate)
|
|
270
|
+
})] }),
|
|
271
|
+
/* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
272
|
+
className: "text-text-tertiary",
|
|
273
|
+
children: "Sent"
|
|
274
|
+
}), /* @__PURE__ */ L("div", {
|
|
275
|
+
className: "text-text-primary",
|
|
276
|
+
children: E(o.sentAt)
|
|
277
|
+
})] }),
|
|
278
|
+
/* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
279
|
+
className: "text-text-tertiary",
|
|
280
|
+
children: "Paid"
|
|
281
|
+
}), /* @__PURE__ */ L("div", {
|
|
282
|
+
className: "text-text-primary",
|
|
283
|
+
children: E(o.paidAt)
|
|
284
|
+
})] })
|
|
285
|
+
]
|
|
286
|
+
}),
|
|
287
|
+
o.lineItems && o.lineItems.length > 0 && /* @__PURE__ */ R(b, { children: [/* @__PURE__ */ L("thead", { children: /* @__PURE__ */ R("tr", { children: [
|
|
288
|
+
/* @__PURE__ */ L(w, { children: "Source" }),
|
|
289
|
+
/* @__PURE__ */ L(w, { children: "Description" }),
|
|
290
|
+
/* @__PURE__ */ L(w, {
|
|
291
|
+
className: "text-right",
|
|
292
|
+
children: "Amount"
|
|
293
|
+
})
|
|
294
|
+
] }) }), /* @__PURE__ */ L("tbody", { children: o.lineItems.map((e, t) => /* @__PURE__ */ R("tr", { children: [
|
|
295
|
+
/* @__PURE__ */ L(x, { children: e.sourceType }),
|
|
296
|
+
/* @__PURE__ */ L(x, { children: e.description ?? e.sourceId }),
|
|
297
|
+
/* @__PURE__ */ L(x, {
|
|
298
|
+
className: "text-right",
|
|
299
|
+
children: D(e.amount, o.currency)
|
|
300
|
+
})
|
|
301
|
+
] }, `${e.sourceType}-${e.sourceId}-${t}`)) })] }),
|
|
302
|
+
/* @__PURE__ */ R("div", {
|
|
303
|
+
className: "rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary",
|
|
304
|
+
children: [
|
|
305
|
+
/* @__PURE__ */ R("div", {
|
|
306
|
+
className: "flex justify-between",
|
|
307
|
+
children: [/* @__PURE__ */ L("span", { children: "Subtotal" }), /* @__PURE__ */ L("span", { children: D(o.subtotal, o.currency) })]
|
|
308
|
+
}),
|
|
309
|
+
/* @__PURE__ */ R("div", {
|
|
310
|
+
className: "flex justify-between",
|
|
311
|
+
children: [/* @__PURE__ */ L("span", { children: "Tax" }), /* @__PURE__ */ L("span", { children: D(o.taxAmount, o.currency) })]
|
|
312
|
+
}),
|
|
313
|
+
/* @__PURE__ */ R("div", {
|
|
314
|
+
className: "flex justify-between font-semibold text-text-primary",
|
|
315
|
+
children: [/* @__PURE__ */ L("span", { children: "Total" }), /* @__PURE__ */ L("span", { children: D(o.total, o.currency) })]
|
|
316
|
+
})
|
|
317
|
+
]
|
|
318
|
+
}),
|
|
319
|
+
o.notes && /* @__PURE__ */ R("div", { children: [/* @__PURE__ */ L("div", {
|
|
320
|
+
className: "text-sm text-text-tertiary",
|
|
321
|
+
children: "Notes"
|
|
322
|
+
}), /* @__PURE__ */ L("div", {
|
|
323
|
+
className: "text-sm text-text-primary",
|
|
324
|
+
children: o.notes
|
|
325
|
+
})] })
|
|
326
|
+
] }) : /* @__PURE__ */ L(u, {
|
|
327
|
+
title: "Invoice not found",
|
|
328
|
+
icon: /* @__PURE__ */ L(j, { className: "h-8 w-8" })
|
|
329
|
+
})]
|
|
330
|
+
})
|
|
331
|
+
});
|
|
332
|
+
}, oe = ({ onClose: e, onSaved: i }) => {
|
|
333
|
+
let a = n(), o = t({ pagination: { limit: 100 } }), [s, c] = k({
|
|
164
334
|
clientId: "",
|
|
165
335
|
engagementId: "",
|
|
166
336
|
number: "",
|
|
@@ -170,160 +340,160 @@ var z = [
|
|
|
170
340
|
issueDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
171
341
|
dueDate: "",
|
|
172
342
|
notes: ""
|
|
173
|
-
}), [
|
|
174
|
-
clientId:
|
|
343
|
+
}), [u, d] = k(null), p = r({
|
|
344
|
+
clientId: s.clientId || void 0,
|
|
175
345
|
pagination: { limit: 100 }
|
|
176
|
-
}),
|
|
346
|
+
}), m = (e) => (t) => c((n) => ({
|
|
177
347
|
...n,
|
|
178
348
|
[e]: t.target.value
|
|
179
|
-
})), _ = (Number(
|
|
180
|
-
return /* @__PURE__ */
|
|
349
|
+
})), _ = (Number(s.subtotal) || 0) + (Number(s.taxAmount) || 0);
|
|
350
|
+
return /* @__PURE__ */ L(h, {
|
|
181
351
|
open: !0,
|
|
182
|
-
onClose:
|
|
352
|
+
onClose: e,
|
|
183
353
|
title: "New invoice",
|
|
184
|
-
footer: /* @__PURE__ */
|
|
354
|
+
footer: /* @__PURE__ */ R(I, { children: [/* @__PURE__ */ L(z, {
|
|
185
355
|
variant: "outline",
|
|
186
|
-
onClick:
|
|
356
|
+
onClick: e,
|
|
187
357
|
disabled: a.isPending,
|
|
188
358
|
children: "Cancel"
|
|
189
|
-
}), /* @__PURE__ */
|
|
359
|
+
}), /* @__PURE__ */ L(z, {
|
|
190
360
|
onClick: () => {
|
|
191
|
-
if (
|
|
192
|
-
if (!
|
|
361
|
+
if (d(null), !s.clientId) return d("Select a client.");
|
|
362
|
+
if (!s.number.trim()) return d("Invoice number is required.");
|
|
193
363
|
a.mutate({
|
|
194
|
-
clientId:
|
|
195
|
-
engagementId:
|
|
196
|
-
number:
|
|
197
|
-
currency:
|
|
198
|
-
subtotal: Number(
|
|
199
|
-
taxAmount: Number(
|
|
364
|
+
clientId: s.clientId,
|
|
365
|
+
engagementId: s.engagementId || null,
|
|
366
|
+
number: s.number.trim(),
|
|
367
|
+
currency: s.currency || "USD",
|
|
368
|
+
subtotal: Number(s.subtotal) || 0,
|
|
369
|
+
taxAmount: Number(s.taxAmount) || 0,
|
|
200
370
|
total: _,
|
|
201
|
-
issueDate:
|
|
202
|
-
dueDate:
|
|
203
|
-
notes:
|
|
371
|
+
issueDate: s.issueDate ? new Date(s.issueDate).toISOString() : null,
|
|
372
|
+
dueDate: s.dueDate ? new Date(s.dueDate).toISOString() : null,
|
|
373
|
+
notes: s.notes.trim() || null
|
|
204
374
|
}, {
|
|
205
375
|
onSuccess: () => {
|
|
206
|
-
i(
|
|
376
|
+
i(s.number.trim()), e();
|
|
207
377
|
},
|
|
208
|
-
onError: (e) =>
|
|
378
|
+
onError: (e) => d(e instanceof Error ? e.message : "Failed.")
|
|
209
379
|
});
|
|
210
380
|
},
|
|
211
381
|
disabled: a.isPending,
|
|
212
382
|
children: a.isPending ? "Creating…" : "Create invoice"
|
|
213
383
|
})] }),
|
|
214
|
-
children: /* @__PURE__ */
|
|
384
|
+
children: /* @__PURE__ */ R("div", {
|
|
215
385
|
className: "space-y-3",
|
|
216
386
|
children: [
|
|
217
|
-
|
|
387
|
+
u && /* @__PURE__ */ L(l, {
|
|
218
388
|
tone: "danger",
|
|
219
|
-
children:
|
|
389
|
+
children: u
|
|
220
390
|
}),
|
|
221
|
-
/* @__PURE__ */
|
|
391
|
+
/* @__PURE__ */ R("div", {
|
|
222
392
|
className: "grid grid-cols-2 gap-3",
|
|
223
|
-
children: [/* @__PURE__ */
|
|
393
|
+
children: [/* @__PURE__ */ L(f, {
|
|
224
394
|
label: "Client",
|
|
225
395
|
required: !0,
|
|
226
|
-
children: /* @__PURE__ */
|
|
227
|
-
value:
|
|
228
|
-
onChange:
|
|
229
|
-
children: [/* @__PURE__ */
|
|
396
|
+
children: /* @__PURE__ */ R(g, {
|
|
397
|
+
value: s.clientId,
|
|
398
|
+
onChange: m("clientId"),
|
|
399
|
+
children: [/* @__PURE__ */ L("option", {
|
|
230
400
|
value: "",
|
|
231
401
|
children: "Select…"
|
|
232
|
-
}),
|
|
402
|
+
}), o.data?.items.map((e) => /* @__PURE__ */ L("option", {
|
|
233
403
|
value: e.id,
|
|
234
404
|
children: e.name
|
|
235
405
|
}, e.id))]
|
|
236
406
|
})
|
|
237
|
-
}), /* @__PURE__ */
|
|
407
|
+
}), /* @__PURE__ */ L(f, {
|
|
238
408
|
label: "Number",
|
|
239
409
|
required: !0,
|
|
240
|
-
children: /* @__PURE__ */
|
|
241
|
-
value:
|
|
242
|
-
onChange:
|
|
410
|
+
children: /* @__PURE__ */ L(C, {
|
|
411
|
+
value: s.number,
|
|
412
|
+
onChange: m("number"),
|
|
243
413
|
placeholder: "INV-2026-014"
|
|
244
414
|
})
|
|
245
415
|
})]
|
|
246
416
|
}),
|
|
247
|
-
/* @__PURE__ */
|
|
417
|
+
/* @__PURE__ */ L(f, {
|
|
248
418
|
label: "Engagement (optional)",
|
|
249
|
-
children: /* @__PURE__ */
|
|
250
|
-
value:
|
|
251
|
-
onChange:
|
|
252
|
-
disabled: !
|
|
253
|
-
children: [/* @__PURE__ */
|
|
419
|
+
children: /* @__PURE__ */ R(g, {
|
|
420
|
+
value: s.engagementId,
|
|
421
|
+
onChange: m("engagementId"),
|
|
422
|
+
disabled: !s.clientId,
|
|
423
|
+
children: [/* @__PURE__ */ L("option", {
|
|
254
424
|
value: "",
|
|
255
425
|
children: "None"
|
|
256
|
-
}),
|
|
426
|
+
}), p.data?.items.map((e) => /* @__PURE__ */ L("option", {
|
|
257
427
|
value: e.id,
|
|
258
428
|
children: e.name
|
|
259
429
|
}, e.id))]
|
|
260
430
|
})
|
|
261
431
|
}),
|
|
262
|
-
/* @__PURE__ */
|
|
432
|
+
/* @__PURE__ */ R("div", {
|
|
263
433
|
className: "grid grid-cols-3 gap-3",
|
|
264
434
|
children: [
|
|
265
|
-
/* @__PURE__ */
|
|
435
|
+
/* @__PURE__ */ L(f, {
|
|
266
436
|
label: "Subtotal",
|
|
267
|
-
children: /* @__PURE__ */
|
|
437
|
+
children: /* @__PURE__ */ L(C, {
|
|
268
438
|
type: "number",
|
|
269
439
|
min: "0",
|
|
270
|
-
value:
|
|
271
|
-
onChange:
|
|
440
|
+
value: s.subtotal,
|
|
441
|
+
onChange: m("subtotal")
|
|
272
442
|
})
|
|
273
443
|
}),
|
|
274
|
-
/* @__PURE__ */
|
|
444
|
+
/* @__PURE__ */ L(f, {
|
|
275
445
|
label: "Tax",
|
|
276
|
-
children: /* @__PURE__ */
|
|
446
|
+
children: /* @__PURE__ */ L(C, {
|
|
277
447
|
type: "number",
|
|
278
448
|
min: "0",
|
|
279
|
-
value:
|
|
280
|
-
onChange:
|
|
449
|
+
value: s.taxAmount,
|
|
450
|
+
onChange: m("taxAmount")
|
|
281
451
|
})
|
|
282
452
|
}),
|
|
283
|
-
/* @__PURE__ */
|
|
453
|
+
/* @__PURE__ */ L(f, {
|
|
284
454
|
label: "Currency",
|
|
285
|
-
children: /* @__PURE__ */
|
|
286
|
-
value:
|
|
287
|
-
onChange:
|
|
455
|
+
children: /* @__PURE__ */ L(C, {
|
|
456
|
+
value: s.currency,
|
|
457
|
+
onChange: m("currency"),
|
|
288
458
|
maxLength: 3
|
|
289
459
|
})
|
|
290
460
|
})
|
|
291
461
|
]
|
|
292
462
|
}),
|
|
293
|
-
/* @__PURE__ */
|
|
463
|
+
/* @__PURE__ */ R("div", {
|
|
294
464
|
className: "rounded-lg bg-bg-sunken px-3 py-2 text-sm text-text-secondary",
|
|
295
465
|
children: [
|
|
296
466
|
"Total:",
|
|
297
467
|
" ",
|
|
298
|
-
/* @__PURE__ */
|
|
468
|
+
/* @__PURE__ */ L("span", {
|
|
299
469
|
className: "font-semibold text-text-primary",
|
|
300
|
-
children:
|
|
470
|
+
children: D(_, s.currency)
|
|
301
471
|
})
|
|
302
472
|
]
|
|
303
473
|
}),
|
|
304
|
-
/* @__PURE__ */
|
|
474
|
+
/* @__PURE__ */ R("div", {
|
|
305
475
|
className: "grid grid-cols-2 gap-3",
|
|
306
|
-
children: [/* @__PURE__ */
|
|
476
|
+
children: [/* @__PURE__ */ L(f, {
|
|
307
477
|
label: "Issue date",
|
|
308
|
-
children: /* @__PURE__ */
|
|
478
|
+
children: /* @__PURE__ */ L(C, {
|
|
309
479
|
type: "date",
|
|
310
|
-
value:
|
|
311
|
-
onChange:
|
|
480
|
+
value: s.issueDate,
|
|
481
|
+
onChange: m("issueDate")
|
|
312
482
|
})
|
|
313
|
-
}), /* @__PURE__ */
|
|
483
|
+
}), /* @__PURE__ */ L(f, {
|
|
314
484
|
label: "Due date",
|
|
315
|
-
children: /* @__PURE__ */
|
|
485
|
+
children: /* @__PURE__ */ L(C, {
|
|
316
486
|
type: "date",
|
|
317
|
-
value:
|
|
318
|
-
onChange:
|
|
487
|
+
value: s.dueDate,
|
|
488
|
+
onChange: m("dueDate")
|
|
319
489
|
})
|
|
320
490
|
})]
|
|
321
491
|
}),
|
|
322
|
-
/* @__PURE__ */
|
|
492
|
+
/* @__PURE__ */ L(f, {
|
|
323
493
|
label: "Notes",
|
|
324
|
-
children: /* @__PURE__ */
|
|
325
|
-
value:
|
|
326
|
-
onChange:
|
|
494
|
+
children: /* @__PURE__ */ L(S, {
|
|
495
|
+
value: s.notes,
|
|
496
|
+
onChange: m("notes")
|
|
327
497
|
})
|
|
328
498
|
})
|
|
329
499
|
]
|
|
@@ -331,6 +501,6 @@ var z = [
|
|
|
331
501
|
});
|
|
332
502
|
};
|
|
333
503
|
//#endregion
|
|
334
|
-
export {
|
|
504
|
+
export { V as InvoicesPage };
|
|
335
505
|
|
|
336
506
|
//# sourceMappingURL=InvoicesPage.js.map
|