@layerfi/components 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  BalanceSheet: () => BalanceSheet,
34
34
  BankTransactions: () => BankTransactions,
35
+ ChartOfAccounts: () => ChartOfAccounts,
35
36
  Hello: () => Hello,
36
37
  LayerProvider: () => LayerProvider,
37
38
  ProfitAndLoss: () => ProfitAndLoss
@@ -39,7 +40,7 @@ __export(src_exports, {
39
40
  module.exports = __toCommonJS(src_exports);
40
41
 
41
42
  // src/components/BalanceSheet/BalanceSheet.tsx
42
- var import_react5 = __toESM(require("react"));
43
+ var import_react6 = __toESM(require("react"));
43
44
 
44
45
  // src/api/util.ts
45
46
  var formStringFromObject = (object) => Object.entries(object).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
@@ -49,7 +50,6 @@ var authenticate = ({
49
50
  appId,
50
51
  appSecret,
51
52
  authenticationUrl = "https://auth.layerfi.com/oauth2/token",
52
- clientId,
53
53
  scope
54
54
  }) => () => fetch(authenticationUrl, {
55
55
  method: "POST",
@@ -60,7 +60,7 @@ var authenticate = ({
60
60
  body: formStringFromObject({
61
61
  grant_type: "client_credentials",
62
62
  scope,
63
- client_id: clientId
63
+ client_id: appId
64
64
  })
65
65
  }).then((res) => res.json());
66
66
 
@@ -207,23 +207,82 @@ var balance_sheet_default = {
207
207
  // src/api/layer/balance_sheet.ts
208
208
  var getBalanceSheet = (_token, _params) => () => balance_sheet_default;
209
209
 
210
+ // src/models/APIError.ts
211
+ var APIError = class _APIError extends Error {
212
+ constructor(message, code, messages) {
213
+ super(message);
214
+ this.name = "APIError";
215
+ this.code = code;
216
+ this.messages = messages;
217
+ Object.setPrototypeOf(this, _APIError.prototype);
218
+ }
219
+ getMessage() {
220
+ return this.message;
221
+ }
222
+ getAllMessages() {
223
+ return this.messages?.map((x) => x.description);
224
+ }
225
+ };
226
+
210
227
  // src/api/layer/authenticated_http.ts
211
- var get = (url) => (accessToken, options) => () => fetch(url(options?.params || {}), {
228
+ var get = (url) => (baseUrl, accessToken, options) => () => fetch(`${baseUrl}${url(options?.params || {})}`, {
212
229
  headers: {
213
230
  Authorization: "Bearer " + (accessToken || ""),
214
231
  "Content-Type": "application/json"
215
232
  },
216
233
  method: "GET"
217
- }).then((res) => res.json());
218
- var put = (url) => (accessToken, options) => fetch(url(options?.params || {}), {
234
+ }).then((res) => handleResponse(res)).catch((error) => handleException(error));
235
+ var request = (verb) => (url) => (baseUrl, accessToken, options) => fetch(`${baseUrl}${url(options?.params || {})}`, {
219
236
  headers: {
220
237
  Authorization: "Bearer " + (accessToken || ""),
221
238
  "Content-Type": "application/json",
222
239
  "Cache-Control": "no-cache"
223
240
  },
224
- method: "PUT",
241
+ method: verb.toUpperCase(),
225
242
  body: JSON.stringify(options?.body)
226
- }).then((res) => res.json());
243
+ }).then((res) => handleResponse(res)).catch((error) => handleException(error));
244
+ var post = request("post");
245
+ var put = request("put");
246
+ var handleResponse = async (res) => {
247
+ if (!res.ok) {
248
+ const errors = await tryToReadErrorsFromResponse(res);
249
+ const apiError = new APIError(
250
+ "An error occurred while fetching the data from API.",
251
+ res.status,
252
+ errors
253
+ );
254
+ throw apiError;
255
+ }
256
+ const parsedResponse = await res.json();
257
+ if (parsedResponse && "errors" in parsedResponse) {
258
+ const apiError = new APIError(
259
+ "Errors in the API response.",
260
+ res.status,
261
+ parsedResponse.errors ?? []
262
+ );
263
+ throw apiError;
264
+ }
265
+ return parsedResponse;
266
+ };
267
+ var handleException = async (error) => {
268
+ if (error.name === "APIError") {
269
+ throw error;
270
+ }
271
+ const apiError = new APIError(
272
+ "An error occurred while parsing the data from API.",
273
+ void 0,
274
+ []
275
+ );
276
+ throw apiError;
277
+ };
278
+ var tryToReadErrorsFromResponse = async (res) => {
279
+ try {
280
+ const data = await res?.json();
281
+ return data?.errors ?? [];
282
+ } catch (_err) {
283
+ return [];
284
+ }
285
+ };
227
286
 
228
287
  // src/api/layer/bankTransactions.ts
229
288
  var getBankTransactions = get(
@@ -231,29 +290,37 @@ var getBankTransactions = get(
231
290
  businessId,
232
291
  sortBy = "date",
233
292
  sortOrder = "DESC"
234
- }) => `https://sandbox.layerfi.com/v1/businesses/${businessId}/bank-transactions?sort_by=${sortBy}&sort_order=${sortOrder}`
293
+ }) => `/v1/businesses/${businessId}/bank-transactions?sort_by=${sortBy}&sort_order=${sortOrder}`
235
294
  );
236
295
  var categorizeBankTransaction = put(
237
- ({ businessId, bankTransactionId }) => `https://sandbox.layerfi.com/v1/businesses/${businessId}/bank-transactions/${bankTransactionId}/categorize`
296
+ ({ businessId, bankTransactionId }) => `/v1/businesses/${businessId}/bank-transactions/${bankTransactionId}/categorize`
238
297
  );
239
298
 
240
299
  // src/api/layer/categories.ts
241
- var getCategories = get(
242
- ({ businessId }) => `https://sandbox.layerfi.com/v1/businesses/${businessId}/categories`
300
+ var getCategories = get(({ businessId }) => `/v1/businesses/${businessId}/categories`);
301
+
302
+ // src/api/layer/chart_of_accounts.ts
303
+ var getChartOfAccounts = get(
304
+ ({ businessId }) => `/v1/businesses/${businessId}/ledger/accounts`
305
+ );
306
+ var createAccount = post(
307
+ ({ businessId }) => `/v1/businesses/${businessId}/ledger/accounts`
243
308
  );
244
309
 
245
310
  // src/api/layer/profit_and_loss.ts
246
311
  var getProfitAndLoss = get(
247
- ({ businessId, startDate, endDate }) => `https://sandbox.layerfi.com/v1/businesses/${businessId}/reports/profit-and-loss?start_date=${startDate}&end_date=${endDate}`
312
+ ({ businessId, startDate, endDate }) => `/v1/businesses/${businessId}/reports/profit-and-loss?start_date=${startDate ? encodeURIComponent(startDate) : ""}&end_date=${endDate ? encodeURIComponent(endDate) : ""}`
248
313
  );
249
314
 
250
315
  // src/api/layer.ts
251
316
  var Layer = {
252
317
  authenticate,
253
318
  categorizeBankTransaction,
319
+ createAccount,
254
320
  getBalanceSheet,
255
321
  getBankTransactions,
256
322
  getCategories,
323
+ getChartOfAccounts,
257
324
  getProfitAndLoss
258
325
  };
259
326
 
@@ -263,9 +330,17 @@ var import_react2 = require("react");
263
330
  // src/contexts/LayerContext/LayerContext.tsx
264
331
  var import_react = require("react");
265
332
  var LayerContext = (0, import_react.createContext)({
266
- auth: { access_token: "", expires_in: -1, token_type: "" },
333
+ auth: {
334
+ access_token: "",
335
+ expires_at: new Date(2e3, 1, 1),
336
+ expires_in: -1,
337
+ token_type: ""
338
+ },
267
339
  businessId: "",
268
- categories: []
340
+ categories: [],
341
+ apiUrl: "",
342
+ theme: void 0,
343
+ setTheme: () => void 0
269
344
  });
270
345
 
271
346
  // src/hooks/useLayerContext/useLayerContext.tsx
@@ -274,7 +349,7 @@ var useLayerContext = () => (0, import_react2.useContext)(LayerContext);
274
349
  // src/hooks/useBalanceSheet/useBalanceSheet.tsx
275
350
  var import_date_fns = require("date-fns");
276
351
  var import_swr = __toESM(require("swr"));
277
- var useBalanceSheet = (date) => {
352
+ var useBalanceSheet = (date = /* @__PURE__ */ new Date()) => {
278
353
  const { auth, businessId } = useLayerContext();
279
354
  const dateString = (0, import_date_fns.format)((0, import_date_fns.startOfDay)(date), "yyyy-mm-dd");
280
355
  const { data, isLoading, error } = (0, import_swr.default)(
@@ -358,67 +433,44 @@ var import_react4 = __toESM(require("react"));
358
433
 
359
434
  // src/icons/ChevronDown.tsx
360
435
  var React4 = __toESM(require("react"));
361
- var ChevronDown = ({ size = 24, ...props }) => /* @__PURE__ */ React4.createElement(
436
+ var ChevronDown = ({ size = 18, ...props }) => /* @__PURE__ */ React4.createElement(
362
437
  "svg",
363
438
  {
439
+ viewBox: "0 0 18 18",
440
+ fill: "none",
364
441
  xmlns: "http://www.w3.org/2000/svg",
442
+ ...props,
365
443
  width: size,
366
- height: size,
367
- fill: "none",
368
- viewBox: "0 0 24 24",
369
- ...props
444
+ height: size
370
445
  },
371
446
  /* @__PURE__ */ React4.createElement(
372
447
  "path",
373
448
  {
449
+ d: "M4.5 6.75L9 11.25L13.5 6.75",
450
+ stroke: "currentColor",
374
451
  strokeLinecap: "round",
375
- strokeLinejoin: "round",
376
- strokeWidth: 2,
377
- d: "m6 9 6 6 6-6"
452
+ strokeLinejoin: "round"
378
453
  }
379
454
  )
380
455
  );
381
456
  var ChevronDown_default = ChevronDown;
382
457
 
383
- // src/icons/ChevronRight.tsx
384
- var React5 = __toESM(require("react"));
385
- var ChavronRight = ({ strokeColor, size, ...props }) => /* @__PURE__ */ React5.createElement(
386
- "svg",
387
- {
388
- xmlns: "http://www.w3.org/2000/svg",
389
- width: size || 24,
390
- height: size || 24,
391
- fill: "none",
392
- viewBox: "0 0 24 24",
393
- ...props
394
- },
395
- /* @__PURE__ */ React5.createElement(
396
- "path",
397
- {
398
- stroke: strokeColor ?? "#000",
399
- strokeLinecap: "round",
400
- strokeLinejoin: "round",
401
- strokeWidth: 2,
402
- d: "m9 18 6-6-6-6"
403
- }
404
- )
405
- );
406
- var ChevronRight_default = ChavronRight;
407
-
408
458
  // src/models/Money.ts
409
459
  var formatter = new Intl.NumberFormat("en-US", {
410
460
  minimumIntegerDigits: 1,
411
461
  minimumFractionDigits: 2,
412
462
  maximumFractionDigits: 2
413
463
  });
414
- var centsToDollars = (cents) => formatter.format(cents / 100);
415
- var dollarsToCents = (dollars) => Math.round(parseFloat(dollars) * 100);
464
+ var centsToDollars = (cents = NaN) => isNaN(cents) ? "-.--" : formatter.format(cents / 100);
465
+ var dollarsToCents = (dollars = "") => Math.round(parseFloat(dollars) * 100);
416
466
 
417
467
  // src/components/BalanceSheetRow/BalanceSheetRow.tsx
418
468
  var BalanceSheetRow = ({
419
469
  lineItem,
420
470
  depth = 0,
421
- maxDepth = 2
471
+ maxDepth = 2,
472
+ variant,
473
+ summarize = true
422
474
  }) => {
423
475
  if (!lineItem) {
424
476
  return null;
@@ -441,9 +493,11 @@ var BalanceSheetRow = ({
441
493
  );
442
494
  labelClasses.push(`Layer__balance-sheet-row__label--depth-${depth}`);
443
495
  valueClasses.push(`Layer__balance-sheet-row__value--depth-${depth}`);
496
+ variant && labelClasses.push(`Layer__balance-sheet-row__label--variant-${variant}`);
497
+ variant && valueClasses.push(`Layer__balance-sheet-row__value--variant-${variant}`);
444
498
  const toggleExpanded = () => setExpanded(!expanded);
445
499
  const canGoDeeper = depth < maxDepth;
446
- const hasChildren = line_items?.length > 0;
500
+ const hasChildren = (line_items?.length ?? 0) > 0;
447
501
  const displayChildren = hasChildren && canGoDeeper;
448
502
  labelClasses.push(
449
503
  `Layer__balance-sheet-row__label--display-children-${displayChildren}`
@@ -451,21 +505,68 @@ var BalanceSheetRow = ({
451
505
  valueClasses.push(
452
506
  `Layer__balance-sheet-row__value--display-children-${displayChildren}`
453
507
  );
454
- return /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("div", { className: labelClasses.join(" "), onClick: toggleExpanded }, expanded ? /* @__PURE__ */ import_react4.default.createElement(ChevronDown_default, { size: 16 }) : /* @__PURE__ */ import_react4.default.createElement(ChevronRight_default, { size: 16 }), display_name), /* @__PURE__ */ import_react4.default.createElement("div", { className: valueClasses.join(" ") }, !!value && amountString), canGoDeeper && hasChildren && expanded && (line_items || []).map((line_item) => /* @__PURE__ */ import_react4.default.createElement(
455
- BalanceSheetRow,
508
+ displayChildren && expanded && labelClasses.push("Layer__balance-sheet-row__label--expanded");
509
+ displayChildren && expanded && valueClasses.push("Layer__balance-sheet-row__value--expanded");
510
+ return /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("div", { className: labelClasses.join(" "), onClick: toggleExpanded }, /* @__PURE__ */ import_react4.default.createElement(ChevronDown_default, { size: 16 }), display_name), /* @__PURE__ */ import_react4.default.createElement("div", { className: valueClasses.join(" ") }, !!value && amountString), canGoDeeper && hasChildren && /* @__PURE__ */ import_react4.default.createElement(
511
+ "div",
456
512
  {
457
- key: line_item.display_name,
458
- lineItem: line_item,
459
- depth: depth + 1,
460
- maxDepth
461
- }
462
- )));
513
+ className: `Layer__balance-sheet-row__children ${expanded && "Layer__balance-sheet-row__children--expanded"}`
514
+ },
515
+ /* @__PURE__ */ import_react4.default.createElement("div", { className: "Layer__balance-sheet-row__children--content" }, (line_items || []).map((line_item, idx) => /* @__PURE__ */ import_react4.default.createElement(
516
+ BalanceSheetRow,
517
+ {
518
+ key: `${line_item.display_name}_${idx}`,
519
+ lineItem: line_item,
520
+ depth: depth + 1,
521
+ maxDepth
522
+ }
523
+ )), summarize && /* @__PURE__ */ import_react4.default.createElement(
524
+ BalanceSheetRow,
525
+ {
526
+ key: display_name,
527
+ lineItem: { value, display_name: `Total of ${display_name}` },
528
+ variant: "summation",
529
+ depth: depth + 1,
530
+ maxDepth
531
+ }
532
+ ))
533
+ ));
534
+ };
535
+
536
+ // src/components/SkeletonBalanceSheetRow/SkeletonBalanceSheetRow.tsx
537
+ var import_react5 = __toESM(require("react"));
538
+ var SkeletonBalanceSheetRow = ({ children }) => {
539
+ const labelClasses = [
540
+ "Layer__balance-sheet-row",
541
+ "Layer__balance-sheet-row__label",
542
+ "Layer__balance-sheet-row__label--skeleton"
543
+ ];
544
+ const valueClasses = [
545
+ "Layer__balance-sheet-row",
546
+ "Layer__balance-sheet-row__value",
547
+ "Layer__balance-sheet-row__value--skeleton"
548
+ ];
549
+ return /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("div", { className: labelClasses.join(" ") }, children && /* @__PURE__ */ import_react5.default.createElement(ChevronDown_default, { size: 16 }), /* @__PURE__ */ import_react5.default.createElement(
550
+ "div",
551
+ {
552
+ style: { width: "20rem" },
553
+ className: "Layer__balance-sheet-row__skeleton-text"
554
+ },
555
+ " "
556
+ )), /* @__PURE__ */ import_react5.default.createElement("div", { className: valueClasses.join(" ") }, /* @__PURE__ */ import_react5.default.createElement(
557
+ "div",
558
+ {
559
+ style: { width: "4rem" },
560
+ className: "Layer__balance-sheet-row__skeleton-text"
561
+ },
562
+ " "
563
+ )), children && /* @__PURE__ */ import_react5.default.createElement("div", { className: "Layer__balance-sheet-row__children Layer__balance-sheet-row__children--expanded Layer__balance-sheet-row__children--skeleton" }, children));
463
564
  };
464
565
 
465
566
  // src/components/BalanceSheet/BalanceSheet.tsx
466
567
  var import_date_fns3 = require("date-fns");
467
568
  var BalanceSheet = () => {
468
- const [effectiveDate, setEffectiveDate] = (0, import_react5.useState)(/* @__PURE__ */ new Date());
569
+ const [effectiveDate, setEffectiveDate] = (0, import_react6.useState)(/* @__PURE__ */ new Date());
469
570
  const { data, isLoading } = useBalanceSheet(effectiveDate);
470
571
  const assets = {
471
572
  name: "Assets",
@@ -480,22 +581,29 @@ var BalanceSheet = () => {
480
581
  value: void 0
481
582
  };
482
583
  const dateString = (0, import_date_fns3.format)(effectiveDate, "LLLL d, yyyy");
483
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "Layer__balance-sheet" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "Layer__balance-sheet__header" }, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "Layer__balance-sheet__title" }, "Balance Sheet", /* @__PURE__ */ import_react5.default.createElement("span", { className: "Layer__balance-sheet__date" }, dateString)), /* @__PURE__ */ import_react5.default.createElement(
584
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "Layer__component Layer__balance-sheet" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "Layer__balance-sheet__header" }, /* @__PURE__ */ import_react6.default.createElement("h2", { className: "Layer__balance-sheet__title" }, "Balance Sheet", /* @__PURE__ */ import_react6.default.createElement("span", { className: "Layer__balance-sheet__date" }, dateString)), /* @__PURE__ */ import_react6.default.createElement(
484
585
  BalanceSheetDatePicker,
485
586
  {
486
587
  value: effectiveDate,
487
588
  onChange: (event) => setEffectiveDate((0, import_date_fns3.parseISO)(event.target.value))
488
589
  }
489
- ), /* @__PURE__ */ import_react5.default.createElement("button", { className: "Layer__balance-sheet__download-button" }, /* @__PURE__ */ import_react5.default.createElement(DownloadCloud_default, null), "Download")), !data || isLoading ? /* @__PURE__ */ import_react5.default.createElement("div", null, "Loading") : /* @__PURE__ */ import_react5.default.createElement("div", { className: "Layer__balance-sheet__table" }, /* @__PURE__ */ import_react5.default.createElement(BalanceSheetRow, { key: assets.name, lineItem: assets }), /* @__PURE__ */ import_react5.default.createElement(BalanceSheetRow, { key: lne.name, lineItem: lne })));
590
+ ), /* @__PURE__ */ import_react6.default.createElement("button", { className: "Layer__balance-sheet__download-button" }, /* @__PURE__ */ import_react6.default.createElement(DownloadCloud_default, null), "Download")), !data || isLoading ? /* @__PURE__ */ import_react6.default.createElement("div", { className: "Layer__balance-sheet__table" }, /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null, /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null), /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null, /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null), /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null))), /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null, /* @__PURE__ */ import_react6.default.createElement(SkeletonBalanceSheetRow, null))) : /* @__PURE__ */ import_react6.default.createElement("div", { className: "Layer__balance-sheet__table" }, /* @__PURE__ */ import_react6.default.createElement(
591
+ BalanceSheetRow,
592
+ {
593
+ key: assets.name,
594
+ lineItem: assets,
595
+ summarize: false
596
+ }
597
+ ), /* @__PURE__ */ import_react6.default.createElement(BalanceSheetRow, { key: lne.name, lineItem: lne, summarize: false })));
490
598
  };
491
599
 
492
600
  // src/components/BankTransactions/BankTransactions.tsx
493
- var import_react12 = __toESM(require("react"));
601
+ var import_react29 = __toESM(require("react"));
494
602
 
495
603
  // src/hooks/useBankTransactions/useBankTransactions.tsx
496
604
  var import_swr2 = __toESM(require("swr"));
497
605
  var useBankTransactions = () => {
498
- const { auth, businessId } = useLayerContext();
606
+ const { auth, businessId, apiUrl } = useLayerContext();
499
607
  const {
500
608
  data: responseData,
501
609
  isLoading,
@@ -503,437 +611,1333 @@ var useBankTransactions = () => {
503
611
  mutate
504
612
  } = (0, import_swr2.default)(
505
613
  businessId && auth?.access_token && `bank-transactions-${businessId}`,
506
- Layer.getBankTransactions(auth?.access_token, { params: { businessId } })
614
+ Layer.getBankTransactions(apiUrl, auth?.access_token, {
615
+ params: { businessId }
616
+ })
507
617
  );
508
618
  const {
509
619
  data = [],
510
620
  meta: metadata = {},
511
621
  error = void 0
512
622
  } = responseData || {};
513
- const categorize = (id, newCategory) => Layer.categorizeBankTransaction(auth.access_token, {
514
- params: { businessId, bankTransactionId: id },
515
- body: newCategory
516
- }).then(({ data: transaction, error: error2 }) => {
517
- if (transaction) {
518
- mutate();
623
+ const categorize = (id, newCategory) => {
624
+ const foundBT = data.find((x) => x.business_id === businessId && x.id === id);
625
+ if (foundBT) {
626
+ updateOneLocal({ ...foundBT, processing: true, error: void 0 });
519
627
  }
520
- if (error2) {
521
- console.error(error2);
522
- throw error2;
628
+ return Layer.categorizeBankTransaction(apiUrl, auth.access_token, {
629
+ params: { businessId, bankTransactionId: id },
630
+ body: newCategory
631
+ }).then(({ data: newBT, errors }) => {
632
+ if (newBT) {
633
+ newBT.recently_categorized = true;
634
+ updateOneLocal(newBT);
635
+ }
636
+ if (errors) {
637
+ console.error(errors);
638
+ throw errors;
639
+ }
640
+ }).catch((err) => {
641
+ const newBT = data.find(
642
+ (x) => x.business_id === businessId && x.id === id
643
+ );
644
+ if (newBT) {
645
+ updateOneLocal({
646
+ ...newBT,
647
+ error: err.message,
648
+ processing: false
649
+ });
650
+ }
651
+ });
652
+ };
653
+ const updateOneLocal = (newBankTransaction) => {
654
+ const updatedData = data.map(
655
+ (bt) => bt.id === newBankTransaction.id ? newBankTransaction : bt
656
+ );
657
+ mutate({ data: updatedData }, { revalidate: false });
658
+ };
659
+ return {
660
+ data,
661
+ metadata,
662
+ isLoading,
663
+ error: responseError || error,
664
+ categorize,
665
+ updateOneLocal
666
+ };
667
+ };
668
+
669
+ // src/hooks/useElementSize/useElementSize.ts
670
+ var import_react7 = require("react");
671
+ var useElementSize = (callback) => {
672
+ const ref = (0, import_react7.useRef)(null);
673
+ (0, import_react7.useLayoutEffect)(() => {
674
+ const element = ref?.current;
675
+ if (!element) {
676
+ return;
523
677
  }
524
- });
525
- return { data, metadata, isLoading, error, categorize };
678
+ const observer = new ResizeObserver((entries) => {
679
+ callback(element, entries[0], {
680
+ width: element.offsetWidth,
681
+ height: element.offsetHeight
682
+ });
683
+ });
684
+ observer.observe(element);
685
+ return () => {
686
+ observer.disconnect();
687
+ };
688
+ }, [callback, ref]);
689
+ return ref;
526
690
  };
527
691
 
528
- // src/components/BankTransactionRow/BankTransactionRow.tsx
529
- var import_react11 = __toESM(require("react"));
692
+ // src/components/BankTransactionListItem/BankTransactionListItem.tsx
693
+ var import_react24 = __toESM(require("react"));
530
694
 
531
- // src/icons/CheckedCircle.tsx
532
- var React8 = __toESM(require("react"));
533
- var CheckedCircle = ({
534
- fillColor = "none",
535
- strokeColor = "#000",
536
- size = 24,
695
+ // src/components/Button/Button.tsx
696
+ var import_react8 = __toESM(require("react"));
697
+ var import_classnames = __toESM(require("classnames"));
698
+ var Button = ({
699
+ className,
700
+ children,
701
+ variant = "primary" /* primary */,
702
+ leftIcon,
703
+ rightIcon,
704
+ iconOnly,
537
705
  ...props
538
- }) => /* @__PURE__ */ React8.createElement(
706
+ }) => {
707
+ let justify = "center";
708
+ if (leftIcon && rightIcon) {
709
+ justify = "space-between";
710
+ } else if (rightIcon) {
711
+ justify = "space-between";
712
+ } else if (leftIcon) {
713
+ justify = "start";
714
+ }
715
+ const baseClassName = (0, import_classnames.default)(
716
+ "Layer__btn",
717
+ `Layer__btn--${variant}`,
718
+ iconOnly ? "Layer__btn--icon-only" : "",
719
+ className
720
+ );
721
+ return /* @__PURE__ */ import_react8.default.createElement("button", { ...props, className: baseClassName }, /* @__PURE__ */ import_react8.default.createElement("span", { className: `Layer__btn-content Layer__justify--${justify}` }, leftIcon && /* @__PURE__ */ import_react8.default.createElement("span", { className: "Layer__btn-icon Layer__btn-icon--left" }, leftIcon), !iconOnly && /* @__PURE__ */ import_react8.default.createElement("span", { className: "Layer__btn-text" }, children), rightIcon && /* @__PURE__ */ import_react8.default.createElement("span", { className: "Layer__btn-icon Layer__btn-icon--right" }, rightIcon)));
722
+ };
723
+
724
+ // src/components/Button/SubmitButton.tsx
725
+ var import_react13 = __toESM(require("react"));
726
+
727
+ // src/icons/AlertCircle.tsx
728
+ var React9 = __toESM(require("react"));
729
+ var AlertCircle = ({ size = 18, ...props }) => /* @__PURE__ */ React9.createElement(
539
730
  "svg",
540
731
  {
732
+ viewBox: "0 0 18 18",
733
+ fill: "none",
541
734
  xmlns: "http://www.w3.org/2000/svg",
735
+ ...props,
542
736
  width: size,
543
- height: size,
544
- viewBox: "0 0 24 24",
545
- fill: fillColor,
546
- ...props
737
+ height: size
547
738
  },
548
- /* @__PURE__ */ React8.createElement(
739
+ /* @__PURE__ */ React9.createElement(
549
740
  "path",
550
741
  {
551
- stroke: strokeColor,
742
+ d: "M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z",
743
+ stroke: "currentColor",
552
744
  strokeLinecap: "round",
553
- strokeLinejoin: "round",
554
- strokeWidth: 2,
555
- d: "m7.5 12 3 3 6-6m5.5 3c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10Z"
745
+ strokeLinejoin: "round"
746
+ }
747
+ ),
748
+ /* @__PURE__ */ React9.createElement(
749
+ "path",
750
+ {
751
+ d: "M9 6V9",
752
+ stroke: "currentColor",
753
+ strokeLinecap: "round",
754
+ strokeLinejoin: "round"
755
+ }
756
+ ),
757
+ /* @__PURE__ */ React9.createElement(
758
+ "path",
759
+ {
760
+ d: "M9 12H9.0075",
761
+ stroke: "currentColor",
762
+ strokeLinecap: "round",
763
+ strokeLinejoin: "round"
556
764
  }
557
765
  )
558
766
  );
559
- var CheckedCircle_default = CheckedCircle;
767
+ var AlertCircle_default = AlertCircle;
560
768
 
561
- // src/icons/ChevronUp.tsx
562
- var React9 = __toESM(require("react"));
563
- var ChevronUp = (props) => /* @__PURE__ */ React9.createElement(
769
+ // src/icons/Check.tsx
770
+ var React10 = __toESM(require("react"));
771
+ var Check = ({ size = 18, ...props }) => /* @__PURE__ */ React10.createElement(
564
772
  "svg",
565
773
  {
566
- xmlns: "http://www.w3.org/2000/svg",
567
- width: 24,
568
- height: 24,
774
+ viewBox: "0 0 18 18",
569
775
  fill: "none",
570
- viewBox: "0 0 24 24",
571
- ...props
776
+ xmlns: "http://www.w3.org/2000/svg",
777
+ ...props,
778
+ width: size,
779
+ height: size
572
780
  },
573
- /* @__PURE__ */ React9.createElement(
781
+ /* @__PURE__ */ React10.createElement(
574
782
  "path",
575
783
  {
576
- stroke: "#000",
784
+ d: "M15 4.5L6.75 12.75L3 9",
785
+ stroke: "currentColor",
577
786
  strokeLinecap: "round",
578
- strokeLinejoin: "round",
579
- strokeWidth: 2,
580
- d: "m18 15-6-6-6 6"
787
+ strokeLinejoin: "round"
581
788
  }
582
789
  )
583
790
  );
584
- var ChevronUp_default = ChevronUp;
585
-
586
- // src/components/CategoryMenu/CategoryMenu.tsx
587
- var import_react6 = __toESM(require("react"));
588
- var import_react_select = __toESM(require("react-select"));
589
- var CategoryMenu = ({
590
- bankTransaction,
591
- name,
592
- value,
593
- onChange
594
- }) => {
595
- const { categories } = useLayerContext();
596
- const suggestedOptions = bankTransaction?.categorization_flow?.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ ? [
597
- {
598
- label: "Suggested",
599
- options: bankTransaction.categorization_flow.suggestions
600
- }
601
- ] : [];
602
- const categoryOptions = (categories || []).map((category) => {
603
- if (category?.subCategories && category?.subCategories?.length > 0) {
604
- return {
605
- label: category.display_name,
606
- options: category.subCategories
607
- };
608
- }
609
- return {
610
- label: category.display_name,
611
- options: [category]
612
- };
613
- }).filter((x) => x);
614
- const options = [...suggestedOptions, ...categoryOptions];
615
- return /* @__PURE__ */ import_react6.default.createElement(
616
- import_react_select.default,
617
- {
618
- name,
619
- className: "Layer__category-menu",
620
- options,
621
- isSearchable: true,
622
- value,
623
- onChange: (newValue) => newValue && onChange(newValue),
624
- getOptionLabel: (category) => category.display_name,
625
- getOptionValue: (category) => category.stable_name || category.category,
626
- menuPortalTarget: document.body,
627
- styles: { menuPortal: (base) => ({ ...base, zIndex: 9999 }) }
628
- }
629
- );
630
- };
631
-
632
- // src/components/ExpandedBankTransactionRow/ExpandedBankTransactionRow.tsx
633
- var import_react9 = __toESM(require("react"));
791
+ var Check_default = Check;
634
792
 
635
- // src/icons/Link.tsx
793
+ // src/icons/CheckCircle.tsx
636
794
  var React11 = __toESM(require("react"));
637
- var Link = ({ size = 24, ...props }) => /* @__PURE__ */ React11.createElement(
795
+ var CheckCircle = ({ size = 18, ...props }) => /* @__PURE__ */ React11.createElement(
638
796
  "svg",
639
797
  {
798
+ viewBox: "0 0 18 18",
799
+ fill: "none",
640
800
  xmlns: "http://www.w3.org/2000/svg",
801
+ ...props,
641
802
  width: size,
642
- height: size,
643
- fill: "none",
644
- viewBox: "0 0 24 24",
645
- ...props
803
+ height: size
646
804
  },
647
805
  /* @__PURE__ */ React11.createElement(
648
806
  "path",
649
807
  {
650
- stroke: "#000",
808
+ d: "M16.5 8.30999V8.99999C16.4991 10.6173 15.9754 12.191 15.007 13.4864C14.0386 14.7817 12.6775 15.7293 11.1265 16.1879C9.57557 16.6465 7.91794 16.5914 6.40085 16.0309C4.88375 15.4704 3.58848 14.4346 2.70821 13.0778C1.82794 11.721 1.40984 10.116 1.51625 8.50223C1.62266 6.88841 2.2479 5.35223 3.2987 4.12279C4.34951 2.89335 5.76958 2.03653 7.34713 1.6801C8.92469 1.32367 10.5752 1.48674 12.0525 2.14499",
809
+ stroke: "currentColor",
651
810
  strokeLinecap: "round",
652
- strokeLinejoin: "round",
653
- strokeWidth: 2,
654
- d: "m12.708 18.364-1.415 1.414a5 5 0 1 1-7.07-7.07l1.413-1.415m12.728 1.414 1.415-1.414a5 5 0 0 0-7.071-7.071l-1.415 1.414M8.5 15.5l7-7"
811
+ strokeLinejoin: "round"
812
+ }
813
+ ),
814
+ /* @__PURE__ */ React11.createElement(
815
+ "path",
816
+ {
817
+ d: "M16.5 3L9 10.5075L6.75 8.2575",
818
+ stroke: "currentColor",
819
+ strokeLinecap: "round",
820
+ strokeLinejoin: "round"
655
821
  }
656
822
  )
657
823
  );
658
- var Link_default = Link;
824
+ var CheckCircle_default = CheckCircle;
659
825
 
660
- // src/icons/LinkBroken.tsx
826
+ // src/icons/Loader.tsx
661
827
  var React12 = __toESM(require("react"));
662
- var LinkBroken = ({ size = 24, ...props }) => /* @__PURE__ */ React12.createElement(
828
+ var Loader = ({ size = 18, ...props }) => /* @__PURE__ */ React12.createElement(
663
829
  "svg",
664
830
  {
831
+ viewBox: "0 0 18 18",
832
+ fill: "none",
665
833
  xmlns: "http://www.w3.org/2000/svg",
834
+ ...props,
666
835
  width: size,
667
- height: size,
668
- fill: "none",
669
- viewBox: "0 0 24 24",
670
- ...props
836
+ height: size
671
837
  },
672
838
  /* @__PURE__ */ React12.createElement(
673
839
  "path",
674
840
  {
675
- stroke: "#000",
841
+ d: "M9 1.5V4.5",
842
+ stroke: "currentColor",
676
843
  strokeLinecap: "round",
677
- strokeLinejoin: "round",
678
- strokeWidth: 2,
679
- d: "m8.5 15.5 7-7M9 4V2m6 18v2M4 9H2m18 6h2M4.914 4.914 3.5 3.5m15.586 15.586L20.5 20.5M12 17.657l-2.121 2.121a4 4 0 1 1-5.657-5.657L6.343 12m11.314 0 2.121-2.121a4 4 0 0 0-5.657-5.657L12 6.343"
844
+ strokeLinejoin: "round"
845
+ }
846
+ ),
847
+ /* @__PURE__ */ React12.createElement(
848
+ "path",
849
+ {
850
+ d: "M9 13.5V16.5",
851
+ stroke: "currentColor",
852
+ strokeLinecap: "round",
853
+ strokeLinejoin: "round"
854
+ }
855
+ ),
856
+ /* @__PURE__ */ React12.createElement(
857
+ "path",
858
+ {
859
+ d: "M3.6975 3.6975L5.82 5.82",
860
+ stroke: "currentColor",
861
+ strokeLinecap: "round",
862
+ strokeLinejoin: "round"
863
+ }
864
+ ),
865
+ /* @__PURE__ */ React12.createElement(
866
+ "path",
867
+ {
868
+ d: "M12.18 12.18L14.3025 14.3025",
869
+ stroke: "currentColor",
870
+ strokeLinecap: "round",
871
+ strokeLinejoin: "round"
872
+ }
873
+ ),
874
+ /* @__PURE__ */ React12.createElement(
875
+ "path",
876
+ {
877
+ d: "M1.5 9H4.5",
878
+ stroke: "currentColor",
879
+ strokeLinecap: "round",
880
+ strokeLinejoin: "round"
881
+ }
882
+ ),
883
+ /* @__PURE__ */ React12.createElement(
884
+ "path",
885
+ {
886
+ d: "M13.5 9H16.5",
887
+ stroke: "currentColor",
888
+ strokeLinecap: "round",
889
+ strokeLinejoin: "round"
890
+ }
891
+ ),
892
+ /* @__PURE__ */ React12.createElement(
893
+ "path",
894
+ {
895
+ d: "M3.6975 14.3025L5.82 12.18",
896
+ stroke: "currentColor",
897
+ strokeLinecap: "round",
898
+ strokeLinejoin: "round"
899
+ }
900
+ ),
901
+ /* @__PURE__ */ React12.createElement(
902
+ "path",
903
+ {
904
+ d: "M12.18 5.82L14.3025 3.6975",
905
+ stroke: "currentColor",
906
+ strokeLinecap: "round",
907
+ strokeLinejoin: "round"
680
908
  }
681
909
  )
682
910
  );
683
- var LinkBroken_default = LinkBroken;
911
+ var Loader_default = Loader;
684
912
 
685
- // src/components/RadioButtonGroup/RadioButtonGroup.tsx
686
- var import_react8 = __toESM(require("react"));
913
+ // src/components/Tooltip/Tooltip.tsx
914
+ var import_react11 = __toESM(require("react"));
687
915
 
688
- // src/components/RadioButtonGroup/RadioButton.tsx
689
- var import_react7 = __toESM(require("react"));
690
- var RadioButton = ({
691
- checked,
692
- label,
693
- name,
694
- onChange,
695
- value,
916
+ // src/components/Tooltip/useTooltip.ts
917
+ var import_react9 = __toESM(require("react"));
918
+ var import_react10 = require("@floating-ui/react");
919
+ var TooltipContext = import_react9.default.createContext(null);
920
+ var useTooltipContext = () => {
921
+ const context = import_react9.default.useContext(TooltipContext);
922
+ if (context == null) {
923
+ throw new Error("Tooltip components must be wrapped in <Tooltip />");
924
+ }
925
+ return context;
926
+ };
927
+ var useTooltip = ({
928
+ initialOpen = false,
929
+ placement = "top",
930
+ open: controlledOpen,
931
+ onOpenChange: setControlledOpen,
696
932
  disabled,
697
- size
698
- }) => {
699
- return /* @__PURE__ */ import_react7.default.createElement(
700
- "label",
701
- {
702
- className: `Layer__radio-button-group__radio-button Layer__radio-button-group__radio-button--size-${size}`
933
+ offset: offsetProp = 5,
934
+ shift: shiftProp = { padding: 5 }
935
+ } = {}) => {
936
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react9.useState)(initialOpen);
937
+ const open = controlledOpen ?? uncontrolledOpen;
938
+ const setOpen = setControlledOpen ?? setUncontrolledOpen;
939
+ const data = (0, import_react10.useFloating)({
940
+ placement,
941
+ open: disabled ? false : open,
942
+ onOpenChange: setOpen,
943
+ whileElementsMounted: import_react10.autoUpdate,
944
+ middleware: [
945
+ (0, import_react10.offset)(offsetProp),
946
+ (0, import_react10.flip)({
947
+ crossAxis: placement.includes("-"),
948
+ fallbackAxisSideDirection: "start",
949
+ padding: shiftProp?.padding ?? 5
950
+ }),
951
+ (0, import_react10.shift)(shiftProp)
952
+ ]
953
+ });
954
+ const context = data.context;
955
+ const hover = (0, import_react10.useHover)(context, {
956
+ move: false,
957
+ enabled: controlledOpen == null
958
+ });
959
+ const focus = (0, import_react10.useFocus)(context, {
960
+ enabled: controlledOpen == null
961
+ });
962
+ const dismiss = (0, import_react10.useDismiss)(context);
963
+ const role = (0, import_react10.useRole)(context, { role: "tooltip" });
964
+ const interactions = (0, import_react10.useInteractions)([hover, focus, dismiss, role]);
965
+ const { isMounted, styles } = (0, import_react10.useTransitionStyles)(context, {
966
+ initial: {
967
+ opacity: 0
703
968
  },
704
- /* @__PURE__ */ import_react7.default.createElement(
705
- "input",
706
- {
707
- type: "radio",
708
- checked,
709
- name,
710
- onChange,
711
- value,
712
- disabled: disabled ?? false
713
- }
714
- ),
715
- /* @__PURE__ */ import_react7.default.createElement("div", null, label)
969
+ duration: 200
970
+ });
971
+ return import_react9.default.useMemo(
972
+ () => ({
973
+ open,
974
+ setOpen,
975
+ isMounted,
976
+ styles,
977
+ disabled,
978
+ ...interactions,
979
+ ...data
980
+ }),
981
+ [open, setOpen, interactions, data, styles, disabled]
716
982
  );
717
983
  };
718
984
 
719
- // src/components/RadioButtonGroup/RadioButtonGroup.tsx
720
- var RadioButtonGroup = ({
721
- name,
722
- size = "large",
723
- buttons,
724
- onChange,
725
- selected
985
+ // src/components/Tooltip/Tooltip.tsx
986
+ var import_react12 = require("@floating-ui/react");
987
+ var Tooltip = ({
988
+ children,
989
+ ...options
726
990
  }) => {
727
- const selectedValue = selected || buttons[0].value;
728
- return /* @__PURE__ */ import_react8.default.createElement(
991
+ const tooltip = useTooltip(options);
992
+ return /* @__PURE__ */ import_react11.default.createElement(TooltipContext.Provider, { value: tooltip }, children);
993
+ };
994
+ var TooltipTrigger = (0, import_react11.forwardRef)(function TooltipTrigger2({ children, asChild = false, ...props }, propRef) {
995
+ const context = useTooltipContext();
996
+ const childrenRef = children.ref;
997
+ const ref = (0, import_react12.useMergeRefs)([context.refs.setReference, propRef, childrenRef]);
998
+ if (asChild && (0, import_react11.isValidElement)(children)) {
999
+ return (0, import_react11.cloneElement)(
1000
+ children,
1001
+ context.getReferenceProps({
1002
+ ref,
1003
+ ...props,
1004
+ ...children.props,
1005
+ "data-state": context.open ? "open" : "closed"
1006
+ })
1007
+ );
1008
+ }
1009
+ return /* @__PURE__ */ import_react11.default.createElement(
1010
+ "span",
1011
+ {
1012
+ ref,
1013
+ "data-state": context.open ? "open" : "closed",
1014
+ className: `Layer__tooltip-trigger Layer__tooltip-trigger--${context.open ? "open" : "closed"}`,
1015
+ ...context.getReferenceProps(props)
1016
+ },
1017
+ children
1018
+ );
1019
+ });
1020
+ var TooltipContent = (0, import_react11.forwardRef)(function TooltipContent2({ style, className, ...props }, propRef) {
1021
+ const context = useTooltipContext();
1022
+ const ref = (0, import_react12.useMergeRefs)([context.refs.setFloating, propRef]);
1023
+ if (!context.open || context.disabled)
1024
+ return null;
1025
+ return /* @__PURE__ */ import_react11.default.createElement(import_react12.FloatingPortal, null, /* @__PURE__ */ import_react11.default.createElement(
729
1026
  "div",
730
1027
  {
731
- className: `Layer__radio-button-group Layer__radio-button-group--size-${size}`
1028
+ ref,
1029
+ className,
1030
+ style: {
1031
+ ...context.styles,
1032
+ ...context.floatingStyles,
1033
+ ...style
1034
+ },
1035
+ ...context.getFloatingProps(props)
1036
+ }
1037
+ ));
1038
+ });
1039
+
1040
+ // src/components/Button/SubmitButton.tsx
1041
+ var import_classnames2 = __toESM(require("classnames"));
1042
+ var buildRightIcon = ({
1043
+ processing,
1044
+ error
1045
+ }) => {
1046
+ if (processing) {
1047
+ return /* @__PURE__ */ import_react13.default.createElement(Loader_default, { size: 14, className: "Layer__anim--rotating" });
1048
+ }
1049
+ if (error) {
1050
+ return /* @__PURE__ */ import_react13.default.createElement(Tooltip, { offset: 12 }, /* @__PURE__ */ import_react13.default.createElement(TooltipTrigger, null, /* @__PURE__ */ import_react13.default.createElement(AlertCircle_default, { size: 14 })), /* @__PURE__ */ import_react13.default.createElement(TooltipContent, { className: "Layer__tooltip" }, error));
1051
+ }
1052
+ return /* @__PURE__ */ import_react13.default.createElement("span", null, /* @__PURE__ */ import_react13.default.createElement(Check_default, { className: "Layer__btn-icon--on-active", size: 14 }), /* @__PURE__ */ import_react13.default.createElement(
1053
+ CheckCircle_default,
1054
+ {
1055
+ className: "Layer__btn-icon--on-inactive",
1056
+ size: 14,
1057
+ style: { paddingTop: 4 }
1058
+ }
1059
+ ));
1060
+ };
1061
+ var SubmitButton = ({
1062
+ active,
1063
+ className,
1064
+ processing,
1065
+ disabled,
1066
+ error,
1067
+ children,
1068
+ ...props
1069
+ }) => {
1070
+ const baseClassName = (0, import_classnames2.default)(
1071
+ active ? "Layer__btn--active" : "",
1072
+ className
1073
+ );
1074
+ return /* @__PURE__ */ import_react13.default.createElement(
1075
+ Button,
1076
+ {
1077
+ ...props,
1078
+ className: baseClassName,
1079
+ variant: "primary" /* primary */,
1080
+ disabled: processing || disabled,
1081
+ rightIcon: buildRightIcon({ processing, error })
732
1082
  },
733
- buttons.map((button) => /* @__PURE__ */ import_react8.default.createElement(
734
- RadioButton,
735
- {
736
- ...button,
737
- key: button.value,
738
- name,
739
- size,
740
- checked: selectedValue === button.value,
741
- onChange,
742
- disabled: button.disabled ?? false
743
- }
744
- ))
1083
+ children
745
1084
  );
746
1085
  };
747
1086
 
748
- // src/components/ExpandedBankTransactionRow/ExpandedBankTransactionRow.tsx
749
- var ExpandedBankTransactionRow = ({
1087
+ // src/components/CategoryMenu/CategoryMenu.tsx
1088
+ var import_react14 = __toESM(require("react"));
1089
+ var import_react_select = __toESM(require("react-select"));
1090
+ var DropdownIndicator = (props) => {
1091
+ return /* @__PURE__ */ import_react14.default.createElement(import_react_select.components.DropdownIndicator, { ...props }, /* @__PURE__ */ import_react14.default.createElement(ChevronDown_default, null));
1092
+ };
1093
+ var CategoryMenu = ({
750
1094
  bankTransaction,
751
- close
1095
+ name,
1096
+ value,
1097
+ onChange,
1098
+ disabled,
1099
+ className
752
1100
  }) => {
753
- const { categorize: categorizeBankTransaction2 } = useBankTransactions();
754
- const [purpose, setPurpose] = (0, import_react9.useState)("categorize" /* categorize */);
755
- const defaultCategory = bankTransaction.category || bankTransaction.categorization_flow?.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ && bankTransaction.categorization_flow?.suggestions?.[0];
756
- const [rowState, updateRowState] = (0, import_react9.useState)({
757
- splits: [
1101
+ const { categories } = useLayerContext();
1102
+ const suggestedOptions = bankTransaction?.categorization_flow?.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ ? [
1103
+ {
1104
+ label: "Suggested",
1105
+ options: bankTransaction.categorization_flow.suggestions
1106
+ }
1107
+ ] : [];
1108
+ const categoryOptions = (categories || []).map((category) => {
1109
+ if (category?.subCategories && category?.subCategories?.length > 0) {
1110
+ return {
1111
+ label: category.display_name,
1112
+ options: category.subCategories
1113
+ };
1114
+ }
1115
+ return {
1116
+ label: category.display_name,
1117
+ options: [category]
1118
+ };
1119
+ }).filter((x) => x);
1120
+ const options = [...suggestedOptions, ...categoryOptions];
1121
+ return /* @__PURE__ */ import_react14.default.createElement(
1122
+ import_react_select.default,
1123
+ {
1124
+ name,
1125
+ className: `Layer__category-menu Layer__select ${className ?? ""}`,
1126
+ classNamePrefix: "Layer__select",
1127
+ options,
1128
+ isSearchable: true,
1129
+ value,
1130
+ onChange: (newValue) => newValue && onChange(newValue),
1131
+ getOptionLabel: (category) => category.display_name,
1132
+ getOptionValue: (category) => category.stable_name || category.category,
1133
+ menuPortalTarget: document.body,
1134
+ styles: { menuPortal: (base) => ({ ...base, zIndex: 9999 }) },
1135
+ components: { DropdownIndicator },
1136
+ isDisabled: disabled
1137
+ }
1138
+ );
1139
+ };
1140
+
1141
+ // src/components/ExpandedBankTransactionRow/ExpandedBankTransactionRow.tsx
1142
+ var import_react22 = __toESM(require("react"));
1143
+
1144
+ // src/icons/FolderPlus.tsx
1145
+ var React17 = __toESM(require("react"));
1146
+ var FolderPlus = ({ size = 18, ...props }) => /* @__PURE__ */ React17.createElement(
1147
+ "svg",
1148
+ {
1149
+ viewBox: "0 0 18 18",
1150
+ fill: "none",
1151
+ xmlns: "http://www.w3.org/2000/svg",
1152
+ ...props,
1153
+ width: size,
1154
+ height: size
1155
+ },
1156
+ /* @__PURE__ */ React17.createElement(
1157
+ "path",
1158
+ {
1159
+ d: "M16.5 14.25C16.5 14.6478 16.342 15.0294 16.0607 15.3107C15.7794 15.592 15.3978 15.75 15 15.75H3C2.60218 15.75 2.22064 15.592 1.93934 15.3107C1.65804 15.0294 1.5 14.6478 1.5 14.25V3.75C1.5 3.35218 1.65804 2.97064 1.93934 2.68934C2.22064 2.40804 2.60218 2.25 3 2.25H6.75L8.25 4.5H15C15.3978 4.5 15.7794 4.65804 16.0607 4.93934C16.342 5.22064 16.5 5.60218 16.5 6V14.25Z",
1160
+ stroke: "currentColor",
1161
+ strokeLinecap: "round",
1162
+ strokeLinejoin: "round"
1163
+ }
1164
+ ),
1165
+ /* @__PURE__ */ React17.createElement(
1166
+ "path",
1167
+ {
1168
+ d: "M9 8.25V12.75",
1169
+ stroke: "currentColor",
1170
+ strokeLinecap: "round",
1171
+ strokeLinejoin: "round"
1172
+ }
1173
+ ),
1174
+ /* @__PURE__ */ React17.createElement(
1175
+ "path",
1176
+ {
1177
+ d: "M6.75 10.5H11.25",
1178
+ stroke: "currentColor",
1179
+ strokeLinecap: "round",
1180
+ strokeLinejoin: "round"
1181
+ }
1182
+ )
1183
+ );
1184
+ var FolderPlus_default = FolderPlus;
1185
+
1186
+ // src/icons/Link.tsx
1187
+ var React18 = __toESM(require("react"));
1188
+ var Link = ({ size = 18, ...props }) => /* @__PURE__ */ React18.createElement(
1189
+ "svg",
1190
+ {
1191
+ xmlns: "http://www.w3.org/2000/svg",
1192
+ viewBox: "0 0 18 18",
1193
+ fill: "none",
1194
+ ...props,
1195
+ width: size,
1196
+ height: size
1197
+ },
1198
+ /* @__PURE__ */ React18.createElement(
1199
+ "path",
1200
+ {
1201
+ d: "M7.5 9.75C7.82209 10.1806 8.23302 10.5369 8.70491 10.7947C9.17681 11.0525 9.69863 11.2058 10.235 11.2442C10.7713 11.2827 11.3097 11.2053 11.8135 11.0173C12.3173 10.8294 12.7748 10.5353 13.155 10.155L15.405 7.905C16.0881 7.19774 16.4661 6.25048 16.4575 5.26724C16.449 4.284 16.0546 3.34346 15.3593 2.64818C14.664 1.9529 13.7235 1.55851 12.7403 1.54997C11.757 1.54143 10.8098 1.9194 10.1025 2.6025L8.8125 3.885",
1202
+ stroke: "currentColor",
1203
+ strokeLinecap: "round",
1204
+ strokeLinejoin: "round"
1205
+ }
1206
+ ),
1207
+ /* @__PURE__ */ React18.createElement(
1208
+ "path",
1209
+ {
1210
+ d: "M10.5 8.25C10.1779 7.8194 9.76698 7.46311 9.29508 7.2053C8.82319 6.94748 8.30137 6.79416 7.76501 6.75575C7.22865 6.71734 6.69031 6.79473 6.18649 6.98266C5.68267 7.1706 5.22516 7.4647 4.845 7.845L2.595 10.095C1.9119 10.8023 1.53393 11.7495 1.54247 12.7328C1.55101 13.716 1.9454 14.6565 2.64068 15.3518C3.33596 16.0471 4.2765 16.4415 5.25974 16.45C6.24298 16.4586 7.19024 16.0806 7.8975 15.3975L9.18 14.115",
1211
+ stroke: "currentColor",
1212
+ strokeLinecap: "round",
1213
+ strokeLinejoin: "round"
1214
+ }
1215
+ )
1216
+ );
1217
+ var Link_default = Link;
1218
+
1219
+ // src/icons/RefreshCcw.tsx
1220
+ var React19 = __toESM(require("react"));
1221
+ var RefreshCcw = ({ size = 18, ...props }) => /* @__PURE__ */ React19.createElement(
1222
+ "svg",
1223
+ {
1224
+ viewBox: "0 0 18 18",
1225
+ fill: "none",
1226
+ xmlns: "http://www.w3.org/2000/svg",
1227
+ ...props,
1228
+ width: size,
1229
+ height: size
1230
+ },
1231
+ /* @__PURE__ */ React19.createElement(
1232
+ "path",
1233
+ {
1234
+ d: "M0.75 3V7.5H5.25",
1235
+ stroke: "currentColor",
1236
+ strokeLinecap: "round",
1237
+ strokeLinejoin: "round"
1238
+ }
1239
+ ),
1240
+ /* @__PURE__ */ React19.createElement(
1241
+ "path",
1242
+ {
1243
+ d: "M17.25 15V10.5H12.75",
1244
+ stroke: "currentColor",
1245
+ strokeLinecap: "round",
1246
+ strokeLinejoin: "round"
1247
+ }
1248
+ ),
1249
+ /* @__PURE__ */ React19.createElement(
1250
+ "path",
1251
+ {
1252
+ d: "M15.3675 6.75C14.9871 5.67508 14.3407 4.71405 13.4884 3.95656C12.6361 3.19907 11.6059 2.66982 10.4938 2.41819C9.38167 2.16656 8.22393 2.20075 7.12861 2.51758C6.03328 2.8344 5.03606 3.42353 4.23 4.23L0.75 7.5M17.25 10.5L13.77 13.77C12.9639 14.5765 11.9667 15.1656 10.8714 15.4824C9.77607 15.7992 8.61833 15.8334 7.50621 15.5818C6.3941 15.3302 5.36385 14.8009 4.5116 14.0434C3.65935 13.2859 3.01288 12.3249 2.6325 11.25",
1253
+ stroke: "currentColor",
1254
+ strokeLinecap: "round",
1255
+ strokeLinejoin: "round"
1256
+ }
1257
+ )
1258
+ );
1259
+ var RefreshCcw_default = RefreshCcw;
1260
+
1261
+ // src/icons/ScissorsFullOpen.tsx
1262
+ var React20 = __toESM(require("react"));
1263
+ var ScissorsFullOpen = ({ size = 12, ...props }) => /* @__PURE__ */ React20.createElement(
1264
+ "svg",
1265
+ {
1266
+ viewBox: "0 0 12 12",
1267
+ fill: "none",
1268
+ xmlns: "http://www.w3.org/2000/svg",
1269
+ ...props,
1270
+ width: size,
1271
+ height: size
1272
+ },
1273
+ /* @__PURE__ */ React20.createElement("g", { id: "scissors" }, /* @__PURE__ */ React20.createElement(
1274
+ "path",
1275
+ {
1276
+ id: "Vector",
1277
+ d: "M3 4.5C3.82843 4.5 4.5 3.82843 4.5 3C4.5 2.17157 3.82843 1.5 3 1.5C2.17157 1.5 1.5 2.17157 1.5 3C1.5 3.82843 2.17157 4.5 3 4.5Z",
1278
+ stroke: "currentColor",
1279
+ strokeLinecap: "round",
1280
+ strokeLinejoin: "round"
1281
+ }
1282
+ ), /* @__PURE__ */ React20.createElement(
1283
+ "path",
1284
+ {
1285
+ id: "Vector_2",
1286
+ d: "M3 10.5C3.82843 10.5 4.5 9.82843 4.5 9C4.5 8.17157 3.82843 7.5 3 7.5C2.17157 7.5 1.5 8.17157 1.5 9C1.5 9.82843 2.17157 10.5 3 10.5Z",
1287
+ stroke: "currentColor",
1288
+ strokeLinecap: "round",
1289
+ strokeLinejoin: "round"
1290
+ }
1291
+ ), /* @__PURE__ */ React20.createElement(
1292
+ "path",
1293
+ {
1294
+ id: "Vector_3",
1295
+ d: "M10 2L4.06 7.94",
1296
+ stroke: "currentColor",
1297
+ strokeLinecap: "round",
1298
+ strokeLinejoin: "round"
1299
+ }
1300
+ ), /* @__PURE__ */ React20.createElement(
1301
+ "path",
1302
+ {
1303
+ id: "Vector_4",
1304
+ d: "M7.235 7.23999L10 9.99999",
1305
+ stroke: "currentColor",
1306
+ strokeLinecap: "round",
1307
+ strokeLinejoin: "round"
1308
+ }
1309
+ ), /* @__PURE__ */ React20.createElement(
1310
+ "path",
1311
+ {
1312
+ id: "Vector_5",
1313
+ d: "M4.06 4.06006L6 6.00006",
1314
+ stroke: "currentColor",
1315
+ strokeLinecap: "round",
1316
+ strokeLinejoin: "round"
1317
+ }
1318
+ ))
1319
+ );
1320
+ var ScissorsFullOpen_default = ScissorsFullOpen;
1321
+
1322
+ // src/components/Input/Input.tsx
1323
+ var import_react15 = __toESM(require("react"));
1324
+ var import_classnames3 = __toESM(require("classnames"));
1325
+ var Input = ({ className, ...props }) => {
1326
+ const baseClassName = (0, import_classnames3.default)("Layer__input", className);
1327
+ return /* @__PURE__ */ import_react15.default.createElement("input", { ...props, className: baseClassName });
1328
+ };
1329
+
1330
+ // src/components/Input/InputGroup.tsx
1331
+ var import_react18 = __toESM(require("react"));
1332
+
1333
+ // src/components/Typography/Text.tsx
1334
+ var import_react16 = __toESM(require("react"));
1335
+ var import_classnames4 = __toESM(require("classnames"));
1336
+ var Text = ({
1337
+ as: Component = "p",
1338
+ className,
1339
+ children,
1340
+ size = "md" /* md */,
1341
+ weight = "normal" /* normal */,
1342
+ withTooltip,
1343
+ ...props
1344
+ }) => {
1345
+ const baseClassName = (0, import_classnames4.default)(
1346
+ `Layer__text Layer__text--${size} Layer__text--${weight}`,
1347
+ className
1348
+ );
1349
+ if (withTooltip) {
1350
+ return /* @__PURE__ */ import_react16.default.createElement(
1351
+ TextWithTooltip,
758
1352
  {
759
- amount: bankTransaction.amount,
760
- inputValue: centsToDollars(bankTransaction.amount),
761
- category: defaultCategory
762
- }
763
- ],
764
- description: "",
765
- file: void 0
766
- });
767
- const addSplit = () => updateRowState({
768
- ...rowState,
769
- splits: [
770
- ...rowState.splits,
771
- { amount: 0, inputValue: "0.00", category: defaultCategory }
772
- ]
773
- });
774
- const removeSplit = () => updateRowState({
775
- ...rowState,
776
- splits: rowState.splits.slice(0, -1)
777
- });
778
- const updateAmounts = (rowNumber) => (event) => {
779
- const newAmount = dollarsToCents(event.target.value) || 0;
780
- const newDisplaying = event.target.value;
781
- const splitTotal = rowState.splits.slice(0, -1).reduce((sum, split, index) => {
782
- const amount = index === rowNumber ? newAmount : split.amount;
783
- return sum + amount;
784
- }, 0);
785
- const remaining = bankTransaction.amount - splitTotal;
786
- rowState.splits[rowNumber].amount = newAmount;
787
- rowState.splits[rowNumber].inputValue = newDisplaying;
788
- rowState.splits[rowState.splits.length - 1].amount = remaining;
789
- rowState.splits[rowState.splits.length - 1].inputValue = centsToDollars(remaining);
790
- updateRowState({ ...rowState });
791
- };
792
- const onBlur = (event) => {
793
- if (event.target.value === "") {
794
- const [_, index] = event.target.name.split("-");
795
- rowState.splits[parseInt(index)].inputValue = "0.00";
796
- updateRowState({ ...rowState });
1353
+ as: Component,
1354
+ className: baseClassName,
1355
+ size,
1356
+ weight,
1357
+ withTooltip,
1358
+ ...props
1359
+ },
1360
+ children
1361
+ );
1362
+ }
1363
+ return /* @__PURE__ */ import_react16.default.createElement(Component, { ...props, className: baseClassName }, children);
1364
+ };
1365
+ var TextWithTooltip = ({
1366
+ as: Component = "p",
1367
+ className,
1368
+ children,
1369
+ size = "md" /* md */,
1370
+ weight = "normal" /* normal */,
1371
+ withTooltip = "whenTruncated" /* whenTruncated */,
1372
+ tooltipOptions,
1373
+ ...props
1374
+ }) => {
1375
+ const textElementRef = (0, import_react16.useRef)();
1376
+ const compareSize = () => {
1377
+ if (textElementRef.current) {
1378
+ const compare = textElementRef.current.children[0].scrollWidth > textElementRef.current.children[0].clientWidth;
1379
+ setHover(compare);
797
1380
  }
798
1381
  };
799
- const onChangePurpose = (event) => setPurpose(
800
- event.target.value === "match" /* match */ ? "match" /* match */ : "categorize" /* categorize */
1382
+ (0, import_react16.useEffect)(() => {
1383
+ compareSize();
1384
+ window.addEventListener("resize", compareSize);
1385
+ }, []);
1386
+ (0, import_react16.useEffect)(
1387
+ () => () => {
1388
+ window.removeEventListener("resize", compareSize);
1389
+ },
1390
+ []
801
1391
  );
802
- const changeCategory = (index, newValue) => {
803
- rowState.splits[index].category = newValue;
804
- updateRowState({ ...rowState });
1392
+ const [hoverStatus, setHover] = (0, import_react16.useState)(false);
1393
+ const contentClassName = (0, import_classnames4.default)(
1394
+ "Layer__tooltip",
1395
+ tooltipOptions?.contentClassName
1396
+ );
1397
+ return /* @__PURE__ */ import_react16.default.createElement(
1398
+ Tooltip,
1399
+ {
1400
+ disabled: !hoverStatus,
1401
+ offset: tooltipOptions?.offset,
1402
+ shift: tooltipOptions?.shift
1403
+ },
1404
+ /* @__PURE__ */ import_react16.default.createElement(TooltipTrigger, null, /* @__PURE__ */ import_react16.default.createElement(Component, { className, ref: textElementRef, ...props }, children)),
1405
+ /* @__PURE__ */ import_react16.default.createElement(TooltipContent, { className: contentClassName }, children)
1406
+ );
1407
+ };
1408
+
1409
+ // src/components/Typography/Heading.tsx
1410
+ var import_react17 = __toESM(require("react"));
1411
+ var import_classnames5 = __toESM(require("classnames"));
1412
+ var Heading = ({
1413
+ as: Component = "h2",
1414
+ className,
1415
+ children,
1416
+ size = "primary" /* primary */
1417
+ }) => {
1418
+ const baseClassName = (0, import_classnames5.default)(
1419
+ `Layer__heading Layer__heading--${size}`,
1420
+ className
1421
+ );
1422
+ return /* @__PURE__ */ import_react17.default.createElement(Component, { className: baseClassName }, children);
1423
+ };
1424
+
1425
+ // src/components/Input/InputGroup.tsx
1426
+ var import_classnames6 = __toESM(require("classnames"));
1427
+ var InputGroup = ({
1428
+ label,
1429
+ name,
1430
+ className,
1431
+ children
1432
+ }) => {
1433
+ const baseClassName = (0, import_classnames6.default)("Layer__input-group", className);
1434
+ return /* @__PURE__ */ import_react18.default.createElement("div", { className: baseClassName }, label && /* @__PURE__ */ import_react18.default.createElement(
1435
+ Text,
1436
+ {
1437
+ as: "label",
1438
+ size: "sm" /* sm */,
1439
+ className: "Layer__input-label",
1440
+ htmlFor: name
1441
+ },
1442
+ label
1443
+ ), children);
1444
+ };
1445
+
1446
+ // src/components/Input/FileInput.tsx
1447
+ var import_react19 = __toESM(require("react"));
1448
+
1449
+ // src/icons/UploadCloud.tsx
1450
+ var React25 = __toESM(require("react"));
1451
+ var UploadCloud = ({ size = 18, ...props }) => /* @__PURE__ */ React25.createElement(
1452
+ "svg",
1453
+ {
1454
+ viewBox: "0 0 18 18",
1455
+ fill: "none",
1456
+ xmlns: "http://www.w3.org/2000/svg",
1457
+ ...props,
1458
+ width: size,
1459
+ height: size
1460
+ },
1461
+ /* @__PURE__ */ React25.createElement(
1462
+ "path",
1463
+ {
1464
+ d: "M12 12L9 9L6 12",
1465
+ stroke: "currentColor",
1466
+ strokeLinecap: "round",
1467
+ strokeLinejoin: "round"
1468
+ }
1469
+ ),
1470
+ /* @__PURE__ */ React25.createElement(
1471
+ "path",
1472
+ {
1473
+ d: "M9 9V15.75",
1474
+ stroke: "currentColor",
1475
+ strokeLinecap: "round",
1476
+ strokeLinejoin: "round"
1477
+ }
1478
+ ),
1479
+ /* @__PURE__ */ React25.createElement(
1480
+ "path",
1481
+ {
1482
+ d: "M15.2925 13.7925C16.024 13.3937 16.6019 12.7626 16.9349 11.999C17.2679 11.2353 17.3372 10.3824 17.1317 9.57501C16.9262 8.7676 16.4576 8.05162 15.8 7.54007C15.1424 7.02852 14.3332 6.75054 13.5 6.74999H12.555C12.328 5.87192 11.9049 5.05674 11.3175 4.36573C10.7301 3.67473 9.99364 3.12588 9.16358 2.76044C8.33352 2.39501 7.43141 2.22251 6.52509 2.2559C5.61876 2.28929 4.7318 2.52771 3.93088 2.95324C3.12997 3.37876 2.43593 3.98032 1.90097 4.71267C1.366 5.44503 1.00402 6.28914 0.842236 7.18153C0.680453 8.07393 0.72308 8.99139 0.966911 9.86493C1.21074 10.7385 1.64943 11.5454 2.25 12.225",
1483
+ stroke: "currentColor",
1484
+ strokeLinecap: "round",
1485
+ strokeLinejoin: "round"
1486
+ }
1487
+ ),
1488
+ /* @__PURE__ */ React25.createElement(
1489
+ "path",
1490
+ {
1491
+ d: "M12 12L9 9L6 12",
1492
+ stroke: "currentColor",
1493
+ strokeLinecap: "round",
1494
+ strokeLinejoin: "round"
1495
+ }
1496
+ )
1497
+ );
1498
+ var UploadCloud_default = UploadCloud;
1499
+
1500
+ // src/components/Input/FileInput.tsx
1501
+ var FileInput = ({ text = "Upload", onUpload }) => {
1502
+ const hiddenFileInput = (0, import_react19.useRef)(null);
1503
+ const onClick = () => {
1504
+ if (hiddenFileInput.current) {
1505
+ hiddenFileInput.current.click();
1506
+ }
805
1507
  };
806
- const save = () => categorizeBankTransaction2(
807
- bankTransaction.id,
808
- rowState.splits.length === 1 ? {
809
- type: "Category",
810
- category: {
811
- type: "StableName",
812
- stable_name: rowState?.splits[0].category?.stable_name || rowState?.splits[0].category?.category
813
- }
814
- } : {
815
- type: "Split",
816
- entries: rowState.splits.map((split) => ({
817
- category: split.category?.stable_name || split.category?.category,
818
- amount: split.amount
819
- }))
820
- }
821
- ).then(close);
822
- const className = "Layer__expanded-bank-transaction-row";
823
- return /* @__PURE__ */ import_react9.default.createElement("div", { className }, /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__purpose-button` }, /* @__PURE__ */ import_react9.default.createElement(
824
- RadioButtonGroup,
825
- {
826
- name: `purpose-${bankTransaction.id}`,
827
- size: "small",
828
- buttons: [
829
- { value: "categorize", label: "Categorize" },
830
- { value: "match", label: "Match", disabled: true }
831
- ],
832
- selected: purpose,
833
- onChange: onChangePurpose
1508
+ const onChange = (event) => {
1509
+ if (event.target.files && event.target.files.length > 0 && onUpload) {
1510
+ const fileUploaded = event.target.files[0];
1511
+ onUpload(fileUploaded);
834
1512
  }
835
- )), /* @__PURE__ */ import_react9.default.createElement(
836
- "div",
1513
+ };
1514
+ return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement(
1515
+ Button,
837
1516
  {
838
- className: `${className}__content`,
839
- id: `expanded-${bankTransaction.id}`
1517
+ onClick,
1518
+ variant: "secondary" /* secondary */,
1519
+ leftIcon: /* @__PURE__ */ import_react19.default.createElement(UploadCloud_default, null)
840
1520
  },
841
- /* @__PURE__ */ import_react9.default.createElement(
842
- "div",
843
- {
844
- className: `${className}__table-cell ${className}__table-cell--header`
1521
+ text
1522
+ ), /* @__PURE__ */ import_react19.default.createElement(
1523
+ "input",
1524
+ {
1525
+ type: "file",
1526
+ onChange,
1527
+ ref: hiddenFileInput,
1528
+ style: { display: "none" }
1529
+ }
1530
+ ));
1531
+ };
1532
+
1533
+ // src/components/Textarea/Textarea.tsx
1534
+ var import_react20 = __toESM(require("react"));
1535
+ var import_classnames7 = __toESM(require("classnames"));
1536
+ var Textarea = ({
1537
+ className,
1538
+ ...props
1539
+ }) => {
1540
+ const baseClassName = (0, import_classnames7.default)("Layer__textarea", className);
1541
+ return /* @__PURE__ */ import_react20.default.createElement("textarea", { ...props, className: baseClassName });
1542
+ };
1543
+
1544
+ // src/components/Toggle/Toggle.tsx
1545
+ var import_react21 = __toESM(require("react"));
1546
+ var import_classnames8 = __toESM(require("classnames"));
1547
+ var Toggle = ({
1548
+ name,
1549
+ options,
1550
+ selected,
1551
+ onChange,
1552
+ size = "medium" /* medium */
1553
+ }) => {
1554
+ const [currentWidth, setCurrentWidth] = (0, import_react21.useState)(0);
1555
+ const [thumbPos, setThumbPos] = (0, import_react21.useState)({ left: 0, width: 0 });
1556
+ const [initialized, setInitialized] = (0, import_react21.useState)(false);
1557
+ const toggleRef = useElementSize((a, b, c) => {
1558
+ if (c.width && c?.width !== currentWidth) {
1559
+ setCurrentWidth(c.width);
1560
+ }
1561
+ });
1562
+ const selectedValue = selected || options[0].value;
1563
+ const baseClassName = (0, import_classnames8.default)(
1564
+ "Layer__toggle",
1565
+ `Layer__toggle--${size}`,
1566
+ initialized ? "Layer__toggle--initialized" : ""
1567
+ );
1568
+ const handleChange = (e) => {
1569
+ updateThumbPosition(Number(e.target.getAttribute("data-idx") ?? 0));
1570
+ onChange(e);
1571
+ };
1572
+ const updateThumbPosition = (active) => {
1573
+ if (!toggleRef?.current) {
1574
+ return;
1575
+ }
1576
+ const optionsNodes = [...toggleRef.current.children].filter(
1577
+ (c) => c.className.includes("Layer__toggle-option")
1578
+ );
1579
+ let shift2 = 0;
1580
+ let width = thumbPos.width;
1581
+ optionsNodes.forEach((c, i) => {
1582
+ if (i < active) {
1583
+ shift2 = shift2 + c.offsetWidth;
1584
+ } else if (i === active) {
1585
+ width = c.offsetWidth;
845
1586
  }
846
- ),
847
- /* @__PURE__ */ import_react9.default.createElement(
848
- "div",
849
- {
850
- className: `${className}__table-cell ${className}__table-cell--header`
851
- },
852
- "Category"
853
- ),
854
- /* @__PURE__ */ import_react9.default.createElement(
855
- "div",
856
- {
857
- className: `${className}__table-cell ${className}__table-cell--header`
858
- },
859
- "Description"
860
- ),
861
- /* @__PURE__ */ import_react9.default.createElement(
862
- "div",
863
- {
864
- className: `${className}__table-cell ${className}__table-cell--header`
865
- },
866
- "Receipt"
867
- ),
868
- /* @__PURE__ */ import_react9.default.createElement(
869
- "div",
870
- {
871
- className: `${className}__table-cell ${className}__table-cell--header`
1587
+ });
1588
+ shift2 = shift2 + (size === "medium" /* medium */ ? 2 : 1);
1589
+ setThumbPos({ left: shift2, width });
1590
+ };
1591
+ (0, import_react21.useEffect)(() => {
1592
+ const selectedIndex = getSelectedIndex();
1593
+ updateThumbPosition(selectedIndex);
1594
+ setTimeout(() => {
1595
+ setInitialized(true);
1596
+ }, 400);
1597
+ }, []);
1598
+ (0, import_react21.useEffect)(() => {
1599
+ const selectedIndex = getSelectedIndex();
1600
+ updateThumbPosition(selectedIndex);
1601
+ }, [currentWidth]);
1602
+ const getSelectedIndex = () => {
1603
+ let selectedIndex = options.findIndex(
1604
+ (option) => option.value === selectedValue
1605
+ );
1606
+ if (selectedIndex === -1) {
1607
+ return 0;
1608
+ }
1609
+ return selectedIndex;
1610
+ };
1611
+ return /* @__PURE__ */ import_react21.default.createElement("div", { className: baseClassName, ref: toggleRef }, options.map((option, index) => /* @__PURE__ */ import_react21.default.createElement(
1612
+ ToggleOption,
1613
+ {
1614
+ ...option,
1615
+ size,
1616
+ key: option.value,
1617
+ name,
1618
+ checked: selectedValue === option.value,
1619
+ onChange: handleChange,
1620
+ disabled: option.disabled ?? false,
1621
+ index
1622
+ }
1623
+ )), /* @__PURE__ */ import_react21.default.createElement("span", { className: "Layer__toggle__thumb", style: { ...thumbPos } }));
1624
+ };
1625
+ var ToggleOption = ({
1626
+ checked,
1627
+ label,
1628
+ name,
1629
+ onChange,
1630
+ value,
1631
+ size,
1632
+ leftIcon,
1633
+ disabled,
1634
+ index
1635
+ }) => {
1636
+ return /* @__PURE__ */ import_react21.default.createElement("label", { className: `Layer__toggle-option`, "data-checked": checked }, /* @__PURE__ */ import_react21.default.createElement(
1637
+ "input",
1638
+ {
1639
+ type: "radio",
1640
+ checked,
1641
+ name,
1642
+ onChange,
1643
+ value,
1644
+ disabled: disabled ?? false,
1645
+ "data-idx": index
1646
+ }
1647
+ ), /* @__PURE__ */ import_react21.default.createElement("span", { className: "Layer__toggle-option-content" }, leftIcon && /* @__PURE__ */ import_react21.default.createElement("span", { className: "Layer__toggle-option__icon" }, leftIcon), /* @__PURE__ */ import_react21.default.createElement("span", null, label)));
1648
+ };
1649
+
1650
+ // src/components/ExpandedBankTransactionRow/ExpandedBankTransactionRow.tsx
1651
+ var ExpandedBankTransactionRow = (0, import_react22.forwardRef)(
1652
+ ({
1653
+ bankTransaction,
1654
+ isOpen = false,
1655
+ asListItem = false,
1656
+ showSubmitButton = false
1657
+ }, ref) => {
1658
+ const { categorize: categorizeBankTransaction2 } = useBankTransactions();
1659
+ const [purpose, setPurpose] = (0, import_react22.useState)("categorize" /* categorize */);
1660
+ const defaultCategory = bankTransaction.category || bankTransaction.categorization_flow?.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ && bankTransaction.categorization_flow?.suggestions?.[0];
1661
+ const [rowState, updateRowState] = (0, import_react22.useState)({
1662
+ splits: [
1663
+ {
1664
+ amount: bankTransaction.amount,
1665
+ inputValue: centsToDollars(bankTransaction.amount),
1666
+ category: defaultCategory
1667
+ }
1668
+ ],
1669
+ description: "",
1670
+ file: void 0
1671
+ });
1672
+ const addSplit = () => updateRowState({
1673
+ ...rowState,
1674
+ splits: [
1675
+ ...rowState.splits,
1676
+ { amount: 0, inputValue: "0.00", category: defaultCategory }
1677
+ ]
1678
+ });
1679
+ const removeSplit = () => updateRowState({
1680
+ ...rowState,
1681
+ splits: rowState.splits.slice(0, -1)
1682
+ });
1683
+ const updateAmounts = (rowNumber) => (event) => {
1684
+ const newAmount = dollarsToCents(event.target.value) || 0;
1685
+ const newDisplaying = event.target.value;
1686
+ const splitTotal = rowState.splits.slice(0, -1).reduce((sum, split, index) => {
1687
+ const amount = index === rowNumber ? newAmount : split.amount;
1688
+ return sum + amount;
1689
+ }, 0);
1690
+ const remaining = bankTransaction.amount - splitTotal;
1691
+ rowState.splits[rowNumber].amount = newAmount;
1692
+ rowState.splits[rowNumber].inputValue = newDisplaying;
1693
+ rowState.splits[rowState.splits.length - 1].amount = remaining;
1694
+ rowState.splits[rowState.splits.length - 1].inputValue = centsToDollars(remaining);
1695
+ updateRowState({ ...rowState });
1696
+ };
1697
+ const onBlur = (event) => {
1698
+ if (event.target.value === "") {
1699
+ const [_, index] = event.target.name.split("-");
1700
+ rowState.splits[parseInt(index)].inputValue = "0.00";
1701
+ updateRowState({ ...rowState });
872
1702
  }
873
- ),
874
- /* @__PURE__ */ import_react9.default.createElement(
875
- "div",
876
- {
877
- className: `${className}__table-cell ${className}__table-cell--header`
1703
+ };
1704
+ const onChangePurpose = (event) => setPurpose(
1705
+ event.target.value === "match" /* match */ ? "match" /* match */ : "categorize" /* categorize */
1706
+ );
1707
+ const changeCategory = (index, newValue) => {
1708
+ rowState.splits[index].category = newValue;
1709
+ updateRowState({ ...rowState });
1710
+ };
1711
+ const save = () => categorizeBankTransaction2(
1712
+ bankTransaction.id,
1713
+ rowState.splits.length === 1 ? {
1714
+ type: "Category",
1715
+ category: {
1716
+ type: "StableName",
1717
+ stable_name: rowState?.splits[0].category?.stable_name || rowState?.splits[0].category?.category
1718
+ }
1719
+ } : {
1720
+ type: "Split",
1721
+ entries: rowState.splits.map((split) => ({
1722
+ category: split.category?.stable_name || split.category?.category,
1723
+ amount: split.amount
1724
+ }))
878
1725
  }
879
- ),
880
- /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__table-cell` }, rowState.splits.length === 1 ? /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__button--split`, onClick: addSplit }, /* @__PURE__ */ import_react9.default.createElement(LinkBroken_default, { className: `${className}__svg`, size: 18 }), "Split") : /* @__PURE__ */ import_react9.default.createElement(
881
- "div",
1726
+ ).catch((e) => console.error(e));
1727
+ (0, import_react22.useImperativeHandle)(ref, () => ({
1728
+ save
1729
+ }));
1730
+ const className = "Layer__expanded-bank-transaction-row";
1731
+ return /* @__PURE__ */ import_react22.default.createElement(
1732
+ "span",
882
1733
  {
883
- className: `${className}__button--merge`,
884
- onClick: removeSplit
1734
+ className: `${className} ${className}--${isOpen ? "expanded" : "collapsed"}`
885
1735
  },
886
- /* @__PURE__ */ import_react9.default.createElement(Link_default, { className: `${className}__svg`, size: 18 }),
887
- "Merge"
888
- )),
889
- /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__table-cell` }, rowState.splits.map((split, index) => /* @__PURE__ */ import_react9.default.createElement(
890
- "div",
891
- {
892
- className: `${className}__table-cell--split-entry`,
893
- key: `split-${index}`
894
- },
895
- /* @__PURE__ */ import_react9.default.createElement(
896
- CategoryMenu,
1736
+ /* @__PURE__ */ import_react22.default.createElement("span", { className: `${className}__wrapper` }, /* @__PURE__ */ import_react22.default.createElement("div", { className: `${className}__content-toggle` }, /* @__PURE__ */ import_react22.default.createElement(
1737
+ Toggle,
897
1738
  {
898
- bankTransaction,
899
- name: `category-${index}`,
900
- value: split.category,
901
- onChange: (value) => changeCategory(index, value)
1739
+ name: `purpose-${bankTransaction.id}${asListItem ? "-li" : ""}`,
1740
+ size: "small" /* small */,
1741
+ options: [
1742
+ {
1743
+ value: "categorize",
1744
+ label: "Categorize",
1745
+ leftIcon: /* @__PURE__ */ import_react22.default.createElement(FolderPlus_default, { size: 15 })
1746
+ },
1747
+ {
1748
+ value: "match",
1749
+ label: "Match",
1750
+ disabled: true,
1751
+ leftIcon: /* @__PURE__ */ import_react22.default.createElement(RefreshCcw_default, { size: 15 })
1752
+ }
1753
+ ],
1754
+ selected: purpose,
1755
+ onChange: onChangePurpose
902
1756
  }
903
- ),
904
- rowState.splits.length > 1 && /* @__PURE__ */ import_react9.default.createElement(
905
- "input",
1757
+ )), /* @__PURE__ */ import_react22.default.createElement(
1758
+ "div",
906
1759
  {
907
- type: "text",
908
- name: `split-${index}`,
909
- disabled: index + 1 === rowState.splits.length,
910
- onChange: updateAmounts(index),
911
- value: split.inputValue,
912
- onBlur,
913
- className: `${className}__split-amount${split.amount < 0 ? "--negative" : ""}`
1760
+ className: `${className}__content`,
1761
+ id: `expanded-${bankTransaction.id}`
1762
+ },
1763
+ /* @__PURE__ */ import_react22.default.createElement("div", { className: `${className}__splits` }, /* @__PURE__ */ import_react22.default.createElement("div", { className: `${className}__splits-inputs` }, rowState.splits.map((split, index) => /* @__PURE__ */ import_react22.default.createElement(
1764
+ "div",
1765
+ {
1766
+ className: `${className}__table-cell--split-entry`,
1767
+ key: `split-${index}`
1768
+ },
1769
+ rowState.splits.length > 1 && /* @__PURE__ */ import_react22.default.createElement(
1770
+ Input,
1771
+ {
1772
+ type: "text",
1773
+ name: `split-${index}${asListItem ? "-li" : ""}`,
1774
+ disabled: index + 1 === rowState.splits.length,
1775
+ onChange: updateAmounts(index),
1776
+ value: split.inputValue,
1777
+ onBlur,
1778
+ className: `${className}__split-amount${split.amount < 0 ? "--negative" : ""}`
1779
+ }
1780
+ ),
1781
+ /* @__PURE__ */ import_react22.default.createElement(
1782
+ CategoryMenu,
1783
+ {
1784
+ bankTransaction,
1785
+ name: `category-${index}${asListItem ? "-li" : ""}`,
1786
+ value: split.category,
1787
+ onChange: (value) => changeCategory(index, value),
1788
+ className: "Layer__category-menu--full"
1789
+ }
1790
+ )
1791
+ ))), /* @__PURE__ */ import_react22.default.createElement("div", { className: `${className}__splits-buttons` }, rowState.splits.length === 1 ? /* @__PURE__ */ import_react22.default.createElement(
1792
+ Button,
1793
+ {
1794
+ onClick: addSplit,
1795
+ leftIcon: /* @__PURE__ */ import_react22.default.createElement(ScissorsFullOpen_default, { size: 14 }),
1796
+ variant: "secondary" /* secondary */
1797
+ },
1798
+ "Split"
1799
+ ) : /* @__PURE__ */ import_react22.default.createElement(
1800
+ Button,
1801
+ {
1802
+ onClick: removeSplit,
1803
+ leftIcon: /* @__PURE__ */ import_react22.default.createElement(Link_default, { size: 14 }),
1804
+ variant: "secondary" /* secondary */
1805
+ },
1806
+ "Merge"
1807
+ ))),
1808
+ /* @__PURE__ */ import_react22.default.createElement(
1809
+ InputGroup,
1810
+ {
1811
+ className: `${className}__description`,
1812
+ name: "description",
1813
+ label: "Description"
1814
+ },
1815
+ /* @__PURE__ */ import_react22.default.createElement(Textarea, { name: "description", placeholder: "Enter description" })
1816
+ ),
1817
+ /* @__PURE__ */ import_react22.default.createElement("div", { className: `${className}__file-upload` }, /* @__PURE__ */ import_react22.default.createElement(FileInput, { text: "Upload receipt" })),
1818
+ asListItem || showSubmitButton ? /* @__PURE__ */ import_react22.default.createElement("div", { className: `${className}__submit-btn` }, /* @__PURE__ */ import_react22.default.createElement(
1819
+ SubmitButton,
1820
+ {
1821
+ onClick: () => {
1822
+ if (!bankTransaction.processing) {
1823
+ save();
1824
+ }
1825
+ },
1826
+ className: "Layer__bank-transaction__submit-btn",
1827
+ processing: bankTransaction.processing,
1828
+ error: bankTransaction.error,
1829
+ active: true
1830
+ },
1831
+ "Approve"
1832
+ )) : null
1833
+ ))
1834
+ );
1835
+ }
1836
+ );
1837
+
1838
+ // src/components/Pill/Pill.tsx
1839
+ var import_react23 = __toESM(require("react"));
1840
+ var Pill = ({ children }) => /* @__PURE__ */ import_react23.default.createElement("span", { className: "Layer__pill" }, children);
1841
+
1842
+ // src/components/BankTransactionListItem/BankTransactionListItem.tsx
1843
+ var import_classnames9 = __toESM(require("classnames"));
1844
+ var import_date_fns4 = require("date-fns");
1845
+ var isCredit = ({ direction }) => direction === "CREDIT" /* CREDIT */;
1846
+ var BankTransactionListItem = ({
1847
+ dateFormat: dateFormat2,
1848
+ bankTransaction,
1849
+ isOpen,
1850
+ toggleOpen,
1851
+ editable
1852
+ }) => {
1853
+ const expandedRowRef = (0, import_react24.useRef)(null);
1854
+ const [removed, setRemoved] = (0, import_react24.useState)(false);
1855
+ const { categorize: categorizeBankTransaction2 } = useBankTransactions();
1856
+ const [selectedCategory, setSelectedCategory] = (0, import_react24.useState)(
1857
+ bankTransaction.categorization_flow?.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ ? bankTransaction.categorization_flow.suggestions[0] : void 0
1858
+ );
1859
+ const save = () => {
1860
+ if (isOpen && expandedRowRef?.current) {
1861
+ expandedRowRef?.current?.save();
1862
+ toggleOpen(bankTransaction.id);
1863
+ return;
1864
+ }
1865
+ categorizeBankTransaction2(bankTransaction.id, {
1866
+ type: "Category",
1867
+ category: {
1868
+ type: "StableName",
1869
+ stable_name: selectedCategory?.stable_name || selectedCategory?.category || ""
1870
+ }
1871
+ });
1872
+ };
1873
+ if (removed) {
1874
+ return null;
1875
+ }
1876
+ const className = "Layer__bank-transaction-list-item";
1877
+ const openClassName = isOpen ? `${className}--expanded` : "";
1878
+ const rowClassName = (0, import_classnames9.default)(
1879
+ className,
1880
+ bankTransaction.recently_categorized ? "Layer__bank-transaction-row--removing" : "",
1881
+ isOpen ? openClassName : ""
1882
+ );
1883
+ return /* @__PURE__ */ import_react24.default.createElement("li", { className: rowClassName }, /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__heading` }, /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__heading-date` }, (0, import_date_fns4.format)((0, import_date_fns4.parseISO)(bankTransaction.date), dateFormat2)), /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__heading-separator` }), /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__heading-account-name` }, bankTransaction.account_name ?? "")), /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__body` }, /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__body__name` }, bankTransaction.counterparty_name), /* @__PURE__ */ import_react24.default.createElement(
1884
+ "span",
1885
+ {
1886
+ className: `${className}__amount-${isCredit(bankTransaction) ? "credit" : "debit"}`
1887
+ },
1888
+ isCredit(bankTransaction) ? "+$" : " $",
1889
+ centsToDollars(bankTransaction.amount)
1890
+ ), /* @__PURE__ */ import_react24.default.createElement(
1891
+ "div",
1892
+ {
1893
+ onClick: () => toggleOpen(bankTransaction.id),
1894
+ className: "Layer__bank-transaction-row__expand-button"
1895
+ },
1896
+ /* @__PURE__ */ import_react24.default.createElement(
1897
+ ChevronDown_default,
1898
+ {
1899
+ className: `Layer__chevron ${isOpen ? "Layer__chevron__up" : "Layer__chevron__down"}`
1900
+ }
1901
+ )
1902
+ )), /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__expanded-row` }, /* @__PURE__ */ import_react24.default.createElement(
1903
+ ExpandedBankTransactionRow,
1904
+ {
1905
+ ref: expandedRowRef,
1906
+ bankTransaction,
1907
+ close: () => toggleOpen(bankTransaction.id),
1908
+ isOpen,
1909
+ asListItem: true
1910
+ }
1911
+ )), /* @__PURE__ */ import_react24.default.createElement("span", { className: `${className}__base-row` }, editable ? /* @__PURE__ */ import_react24.default.createElement(
1912
+ CategoryMenu,
1913
+ {
1914
+ bankTransaction,
1915
+ name: `category-${bankTransaction.id}`,
1916
+ value: selectedCategory,
1917
+ onChange: setSelectedCategory,
1918
+ disabled: bankTransaction.processing
1919
+ }
1920
+ ) : null, !editable ? /* @__PURE__ */ import_react24.default.createElement(Pill, null, bankTransaction?.category?.display_name) : null, editable && /* @__PURE__ */ import_react24.default.createElement(
1921
+ SubmitButton,
1922
+ {
1923
+ onClick: () => {
1924
+ if (!bankTransaction.processing) {
1925
+ save();
914
1926
  }
915
- )
916
- ))),
917
- /* @__PURE__ */ import_react9.default.createElement(
918
- "div",
919
- {
920
- className: `${className}__table-cell ${className}__table-cell--description`
921
1927
  },
922
- /* @__PURE__ */ import_react9.default.createElement("textarea", null)
923
- ),
924
- /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__table-cell` }, /* @__PURE__ */ import_react9.default.createElement("input", { type: "file" })),
925
- /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__table-cell` }),
926
- /* @__PURE__ */ import_react9.default.createElement("div", { className: `${className}__table-cell` }, /* @__PURE__ */ import_react9.default.createElement("button", { onClick: save, className: `${className}__button--save` }, "Save"))
927
- ));
1928
+ className: "Layer__bank-transaction__submit-btn",
1929
+ processing: bankTransaction.processing,
1930
+ error: bankTransaction.error,
1931
+ iconOnly: true
1932
+ }
1933
+ )));
928
1934
  };
929
1935
 
930
- // src/components/Pill/Pill.tsx
931
- var import_react10 = __toESM(require("react"));
932
- var Pill = ({ children }) => /* @__PURE__ */ import_react10.default.createElement("span", { className: "Layer__pill" }, children);
933
-
934
1936
  // src/components/BankTransactionRow/BankTransactionRow.tsx
935
- var import_date_fns4 = require("date-fns");
936
- var isCredit = ({ direction }) => direction === "CREDIT" /* CREDIT */;
1937
+ var import_react25 = __toESM(require("react"));
1938
+ var import_classnames10 = __toESM(require("classnames"));
1939
+ var import_date_fns5 = require("date-fns");
1940
+ var isCredit2 = ({ direction }) => direction === "CREDIT" /* CREDIT */;
937
1941
  var BankTransactionRow = ({
938
1942
  dateFormat: dateFormat2,
939
1943
  bankTransaction,
@@ -941,65 +1945,269 @@ var BankTransactionRow = ({
941
1945
  toggleOpen,
942
1946
  editable
943
1947
  }) => {
1948
+ const expandedRowRef = (0, import_react25.useRef)(null);
1949
+ const [removed, setRemoved] = (0, import_react25.useState)(false);
944
1950
  const { categorize: categorizeBankTransaction2 } = useBankTransactions();
945
- const [selectedCategory, setSelectedCategory] = (0, import_react11.useState)(
946
- bankTransaction.categorization_flow.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ ? bankTransaction.categorization_flow.suggestions[0] : void 0
1951
+ const [selectedCategory, setSelectedCategory] = (0, import_react25.useState)(
1952
+ bankTransaction.categorization_flow?.type === "ASK_FROM_SUGGESTIONS" /* ASK_FROM_SUGGESTIONS */ ? bankTransaction.categorization_flow.suggestions[0] : void 0
947
1953
  );
948
- const className = "Layer__bank-transaction-row__table-cell";
949
- const openClassName = isOpen ? `${className}--expanded` : "";
950
- const save = () => categorizeBankTransaction2(bankTransaction.id, {
951
- type: "Category",
952
- category: {
953
- type: "StableName",
954
- stable_name: selectedCategory?.stable_name || selectedCategory?.category || ""
1954
+ const save = () => {
1955
+ if (isOpen && expandedRowRef?.current) {
1956
+ expandedRowRef?.current?.save();
1957
+ toggleOpen(bankTransaction.id);
1958
+ return;
955
1959
  }
956
- });
957
- return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement("div", { className: `${className} ${openClassName} ${className}--date` }, (0, import_date_fns4.format)((0, import_date_fns4.parseISO)(bankTransaction.date), dateFormat2)), /* @__PURE__ */ import_react11.default.createElement("div", { className: `${className} ${openClassName}` }, bankTransaction.counterparty_name), /* @__PURE__ */ import_react11.default.createElement("div", { className: `${className} ${openClassName}` }, "Business Checking"), /* @__PURE__ */ import_react11.default.createElement(
958
- "div",
1960
+ categorizeBankTransaction2(bankTransaction.id, {
1961
+ type: "Category",
1962
+ category: {
1963
+ type: "StableName",
1964
+ stable_name: selectedCategory?.stable_name || selectedCategory?.category || ""
1965
+ }
1966
+ });
1967
+ };
1968
+ if (removed) {
1969
+ return null;
1970
+ }
1971
+ const className = "Layer__bank-transaction-row";
1972
+ const openClassName = isOpen ? `${className}--expanded` : "";
1973
+ const rowClassName = (0, import_classnames10.default)(
1974
+ className,
1975
+ bankTransaction.recently_categorized ? "Layer__bank-transaction-row--removing" : "",
1976
+ isOpen ? openClassName : ""
1977
+ );
1978
+ return /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(
1979
+ "tr",
959
1980
  {
960
- className: `${className} ${openClassName} ${className}--amount-${isCredit(bankTransaction) ? "credit" : "debit"}`
1981
+ className: rowClassName,
1982
+ onTransitionEnd: ({ propertyName }) => {
1983
+ if (propertyName === "top") {
1984
+ setRemoved(true);
1985
+ }
1986
+ }
961
1987
  },
962
- centsToDollars(bankTransaction.amount)
963
- ), isOpen ? /* @__PURE__ */ import_react11.default.createElement("div", { className: `${className} ${openClassName}` }) : /* @__PURE__ */ import_react11.default.createElement("div", { className: `${className} ${openClassName}` }, editable ? /* @__PURE__ */ import_react11.default.createElement(
964
- CategoryMenu,
1988
+ /* @__PURE__ */ import_react25.default.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ import_react25.default.createElement("span", { className: "Layer__table-cell-content" }, (0, import_date_fns5.format)((0, import_date_fns5.parseISO)(bankTransaction.date), dateFormat2))),
1989
+ /* @__PURE__ */ import_react25.default.createElement("td", { className: "Layer__table-cell Layer__bank-transactions__tx-col" }, /* @__PURE__ */ import_react25.default.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ import_react25.default.createElement(
1990
+ Text,
1991
+ {
1992
+ as: "span",
1993
+ className: "Layer__bank-transactions__tx-text",
1994
+ withTooltip: "whenTruncated" /* whenTruncated */,
1995
+ tooltipOptions: {
1996
+ contentClassName: "Layer__bank-transactions__tx-tooltip"
1997
+ }
1998
+ },
1999
+ bankTransaction.counterparty_name
2000
+ ))),
2001
+ /* @__PURE__ */ import_react25.default.createElement("td", { className: "Layer__table-cell Layer__bank-transactions__account-col" }, /* @__PURE__ */ import_react25.default.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ import_react25.default.createElement(
2002
+ Text,
2003
+ {
2004
+ as: "span",
2005
+ className: "Layer__bank-transactions__account-text",
2006
+ withTooltip: "whenTruncated" /* whenTruncated */
2007
+ },
2008
+ bankTransaction.account_name ?? ""
2009
+ ))),
2010
+ /* @__PURE__ */ import_react25.default.createElement(
2011
+ "td",
2012
+ {
2013
+ className: `Layer__table-cell Layer__table-cell__amount-col Layer__table-cell--amount ${className}__table-cell--amount-${isCredit2(bankTransaction) ? "credit" : "debit"}`
2014
+ },
2015
+ /* @__PURE__ */ import_react25.default.createElement("span", { className: "Layer__table-cell-content" }, isCredit2(bankTransaction) ? "+$" : " $", centsToDollars(bankTransaction.amount))
2016
+ ),
2017
+ /* @__PURE__ */ import_react25.default.createElement(
2018
+ "td",
2019
+ {
2020
+ className: (0, import_classnames10.default)(
2021
+ "Layer__table-cell",
2022
+ "Layer__table-cell__category-col",
2023
+ `${className}__actions-cell`,
2024
+ `${className}__actions-cell--${isOpen ? "open" : "close"}`
2025
+ )
2026
+ },
2027
+ /* @__PURE__ */ import_react25.default.createElement(
2028
+ "span",
2029
+ {
2030
+ className: `${className}__actions-container Layer__table-cell-content`
2031
+ },
2032
+ editable && !isOpen ? /* @__PURE__ */ import_react25.default.createElement(
2033
+ CategoryMenu,
2034
+ {
2035
+ bankTransaction,
2036
+ name: `category-${bankTransaction.id}`,
2037
+ value: selectedCategory,
2038
+ onChange: setSelectedCategory,
2039
+ disabled: bankTransaction.processing
2040
+ }
2041
+ ) : null,
2042
+ !editable ? /* @__PURE__ */ import_react25.default.createElement(Text, { as: "span", className: `${className}__category-text` }, bankTransaction?.category?.display_name) : null,
2043
+ editable && /* @__PURE__ */ import_react25.default.createElement(
2044
+ SubmitButton,
2045
+ {
2046
+ onClick: () => {
2047
+ if (!bankTransaction.processing) {
2048
+ save();
2049
+ }
2050
+ },
2051
+ className: "Layer__bank-transaction__submit-btn",
2052
+ processing: bankTransaction.processing,
2053
+ error: bankTransaction.error,
2054
+ active: isOpen
2055
+ },
2056
+ "Approve"
2057
+ ),
2058
+ /* @__PURE__ */ import_react25.default.createElement(
2059
+ "div",
2060
+ {
2061
+ onClick: () => toggleOpen(bankTransaction.id),
2062
+ className: "Layer__bank-transaction-row__expand-button"
2063
+ },
2064
+ /* @__PURE__ */ import_react25.default.createElement(
2065
+ ChevronDown_default,
2066
+ {
2067
+ className: `Layer__chevron ${isOpen ? "Layer__chevron__up" : "Layer__chevron__down"}`
2068
+ }
2069
+ )
2070
+ )
2071
+ )
2072
+ )
2073
+ ), /* @__PURE__ */ import_react25.default.createElement("tr", null, /* @__PURE__ */ import_react25.default.createElement("td", { colSpan: 5 }, /* @__PURE__ */ import_react25.default.createElement(
2074
+ ExpandedBankTransactionRow,
965
2075
  {
2076
+ ref: expandedRowRef,
966
2077
  bankTransaction,
967
- name: `category-${bankTransaction.id}`,
968
- value: selectedCategory,
969
- onChange: setSelectedCategory
2078
+ close: () => toggleOpen(bankTransaction.id),
2079
+ isOpen,
2080
+ showSubmitButton: !editable
970
2081
  }
971
- ) : /* @__PURE__ */ import_react11.default.createElement(Pill, null, bankTransaction?.category?.display_name)), /* @__PURE__ */ import_react11.default.createElement("div", { className: `${className} ${openClassName} ${className}--actions` }, /* @__PURE__ */ import_react11.default.createElement(
972
- "div",
973
- {
974
- className: "Layer__bank-transaction-row__save-button",
975
- onClick: () => save()
976
- },
977
- editable && !isOpen && /* @__PURE__ */ import_react11.default.createElement(
978
- CheckedCircle_default,
979
- {
980
- size: 28,
981
- strokeColor: "#0C48E5",
982
- fillColor: "#e0e9ff"
2082
+ ))));
2083
+ };
2084
+
2085
+ // src/components/Container/Container.tsx
2086
+ var import_react26 = __toESM(require("react"));
2087
+
2088
+ // src/utils/colors.ts
2089
+ var parseStylesFromThemeConfig = (theme) => {
2090
+ let styles = {};
2091
+ if (!theme) {
2092
+ return styles;
2093
+ }
2094
+ if (theme.colors) {
2095
+ const darkColor = parseColorFromTheme("dark", theme.colors.dark);
2096
+ const lightColor = parseColorFromTheme("light", theme.colors.light);
2097
+ styles = { ...styles, ...darkColor, ...lightColor };
2098
+ }
2099
+ return styles;
2100
+ };
2101
+ var parseColorFromTheme = (colorName, color) => {
2102
+ if (!color) {
2103
+ return {};
2104
+ }
2105
+ try {
2106
+ if ("h" in color && "s" in color && "l" in color) {
2107
+ console.log("its hsl", color);
2108
+ return {
2109
+ [`--color-${colorName}-h`]: color.h,
2110
+ [`--color-${colorName}-s`]: color.s,
2111
+ [`--color-${colorName}-l`]: color.l
2112
+ };
2113
+ }
2114
+ if ("r" in color && "g" in color && "b" in color) {
2115
+ const { h, s, l } = rgbToHsl(color);
2116
+ console.log("its rgb", h, s, l);
2117
+ return {
2118
+ [`--color-${colorName}-h`]: h,
2119
+ [`--color-${colorName}-s`]: `${s}%`,
2120
+ [`--color-${colorName}-l`]: `${l}%`
2121
+ };
2122
+ }
2123
+ if ("hex" in color) {
2124
+ console.log("its hex");
2125
+ const rgb = hexToRgb(color.hex);
2126
+ if (!rgb) {
2127
+ return {};
983
2128
  }
984
- )
985
- ), /* @__PURE__ */ import_react11.default.createElement(
2129
+ const { h, s, l } = rgbToHsl({
2130
+ r: rgb.r.toString(),
2131
+ g: rgb.g.toString(),
2132
+ b: rgb.b.toString()
2133
+ });
2134
+ console.log("its hex", h, s, l);
2135
+ return {
2136
+ [`--color-${colorName}-h`]: h,
2137
+ [`--color-${colorName}-s`]: `${s}%`,
2138
+ [`--color-${colorName}-l`]: `${l}%`
2139
+ };
2140
+ }
2141
+ return {};
2142
+ } catch (_err) {
2143
+ return {};
2144
+ }
2145
+ };
2146
+ var rgbToHsl = (color) => {
2147
+ let r = Number(color.r);
2148
+ let g = Number(color.g);
2149
+ let b = Number(color.b);
2150
+ r /= 255;
2151
+ g /= 255;
2152
+ b /= 255;
2153
+ const l = Math.max(r, g, b);
2154
+ const s = l - Math.min(r, g, b);
2155
+ const h = s ? l === r ? (g - b) / s : l === g ? 2 + (b - r) / s : 4 + (r - g) / s : 0;
2156
+ return {
2157
+ h: 60 * h < 0 ? 60 * h + 360 : 60 * h,
2158
+ s: 100 * (s ? l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s)) : 0),
2159
+ l: 100 * (2 * l - s) / 2
2160
+ };
2161
+ };
2162
+ var hexToRgb = (hex) => {
2163
+ const values = hex.replace(
2164
+ /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
2165
+ (m, r, g, b) => "#" + r + r + g + g + b + b
2166
+ ).substring(1).match(/.{2}/g)?.map((x) => parseInt(x, 16));
2167
+ if (!values) {
2168
+ return;
2169
+ }
2170
+ return {
2171
+ r: values[0],
2172
+ g: values[1],
2173
+ b: values[2]
2174
+ };
2175
+ };
2176
+
2177
+ // src/components/Container/Container.tsx
2178
+ var Container = ({ name, className, children }) => {
2179
+ const baseClassName = `Layer__${name} ${className ?? ""}`;
2180
+ const { theme } = useLayerContext();
2181
+ const styles = parseStylesFromThemeConfig(theme);
2182
+ return /* @__PURE__ */ import_react26.default.createElement(
986
2183
  "div",
987
2184
  {
988
- onClick: () => toggleOpen(bankTransaction.id),
989
- className: "Layer__bank-transaction-row__expand-button"
2185
+ className: `Layer__component Layer__component-container ${baseClassName}`,
2186
+ style: { ...styles }
990
2187
  },
991
- isOpen ? /* @__PURE__ */ import_react11.default.createElement(ChevronUp_default, null) : /* @__PURE__ */ import_react11.default.createElement(ChevronDown_default, null)
992
- )), isOpen && /* @__PURE__ */ import_react11.default.createElement(
993
- ExpandedBankTransactionRow,
994
- {
995
- bankTransaction,
996
- close: () => toggleOpen(bankTransaction.id)
997
- }
998
- ));
2188
+ children
2189
+ );
2190
+ };
2191
+
2192
+ // src/components/Container/Header.tsx
2193
+ var import_react27 = __toESM(require("react"));
2194
+ var import_classnames11 = __toESM(require("classnames"));
2195
+ var Header = (0, import_react27.forwardRef)(
2196
+ ({ className, children, style }, ref) => {
2197
+ const baseClassName = (0, import_classnames11.default)("Layer__component-header", className);
2198
+ return /* @__PURE__ */ import_react27.default.createElement("header", { ref, className: baseClassName, style }, children);
2199
+ }
2200
+ );
2201
+
2202
+ // src/components/Loader/Loader.tsx
2203
+ var import_react28 = __toESM(require("react"));
2204
+ var Loader2 = ({ children }) => {
2205
+ return /* @__PURE__ */ import_react28.default.createElement("span", { className: "Layer__loader" }, /* @__PURE__ */ import_react28.default.createElement(Loader_default, { size: 14, className: "Layer__anim--rotating" }), children ?? "Loading...");
999
2206
  };
1000
2207
 
1001
2208
  // src/components/BankTransactions/BankTransactions.tsx
1002
- var dateFormat = "MM/dd/yyyy";
2209
+ var COMPONENT_NAME = "bank-transactions";
2210
+ var dateFormat = "LLL d, yyyy";
1003
2211
  var CategorizedCategories = [
1004
2212
  "CATEGORIZED" /* CATEGORIZED */,
1005
2213
  "JOURNALING" /* JOURNALING */,
@@ -1013,46 +2221,83 @@ var filterVisibility = (display) => (bankTransaction) => {
1013
2221
  const categorized = CategorizedCategories.includes(
1014
2222
  bankTransaction.categorization_status
1015
2223
  );
1016
- const inReview = ReviewCategories.includes(
1017
- bankTransaction.categorization_status
1018
- );
2224
+ const inReview = ReviewCategories.includes(bankTransaction.categorization_status) || bankTransaction.recently_categorized;
1019
2225
  return display === "review" /* review */ && inReview || display === "categorized" /* categorized */ && categorized;
1020
2226
  };
1021
2227
  var BankTransactions = () => {
1022
- const [display, setDisplay] = (0, import_react12.useState)("review" /* review */);
1023
- const { data } = useBankTransactions();
2228
+ const [display, setDisplay] = (0, import_react29.useState)("review" /* review */);
2229
+ const { data, isLoading } = useBankTransactions();
1024
2230
  const bankTransactions = data.filter(filterVisibility(display));
1025
2231
  const onCategorizationDisplayChange = (event) => setDisplay(
1026
2232
  event.target.value === "categorized" /* categorized */ ? "categorized" /* categorized */ : "review" /* review */
1027
2233
  );
1028
- const [openRows, setOpenRows] = (0, import_react12.useState)({});
2234
+ const [openRows, setOpenRows] = (0, import_react29.useState)({});
1029
2235
  const toggleOpen = (id) => setOpenRows({ ...openRows, [id]: !openRows[id] });
1030
- return /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions", "data-display": display }, /* @__PURE__ */ import_react12.default.createElement("header", { className: "Layer__bank-transactions__header" }, /* @__PURE__ */ import_react12.default.createElement("h2", { className: "Layer__bank-transactions__title" }, "Transactions"), /* @__PURE__ */ import_react12.default.createElement(
1031
- RadioButtonGroup,
1032
- {
1033
- name: "bank-transaction-display",
1034
- buttons: [
1035
- { label: "To Review", value: "review" /* review */ },
1036
- { label: "Categorized", value: "categorized" /* categorized */ }
1037
- ],
1038
- selected: display,
1039
- onChange: onCategorizationDisplayChange
2236
+ const [shiftStickyHeader, setShiftStickyHeader] = (0, import_react29.useState)(0);
2237
+ const headerRef = useElementSize((_el, _en, size) => {
2238
+ if (size?.height && size?.height >= 90) {
2239
+ const newShift = -Math.floor(size.height / 2) + 6;
2240
+ if (newShift !== shiftStickyHeader) {
2241
+ setShiftStickyHeader(newShift);
2242
+ }
2243
+ } else if (size?.height > 0 && shiftStickyHeader !== 0) {
2244
+ setShiftStickyHeader(0);
1040
2245
  }
1041
- )), /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table-cell Layer__bank-transactions__table-cell--header" }, "Date"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table-cell Layer__bank-transactions__table-cell--header" }, "Transaction"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table-cell Layer__bank-transactions__table-cell--header" }, "Account"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table-cell Layer__bank-transactions__table-cell--header Layer__bank-transactions__table-cell--header-amount" }, "Amount"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table-cell Layer__bank-transactions__table-cell--header" }, "Category"), /* @__PURE__ */ import_react12.default.createElement("div", { className: "Layer__bank-transactions__table-cell Layer__bank-transactions__table-cell--header" }, "Actions"), bankTransactions.map((bankTransaction) => /* @__PURE__ */ import_react12.default.createElement(
1042
- BankTransactionRow,
2246
+ });
2247
+ const editable = display === "review" /* review */;
2248
+ return /* @__PURE__ */ import_react29.default.createElement(Container, { name: COMPONENT_NAME }, /* @__PURE__ */ import_react29.default.createElement(
2249
+ Header,
2250
+ {
2251
+ ref: headerRef,
2252
+ className: "Layer__bank-transactions__header",
2253
+ style: { top: shiftStickyHeader }
2254
+ },
2255
+ /* @__PURE__ */ import_react29.default.createElement(Heading, { className: "Layer__bank-transactions__title" }, "Transactions"),
2256
+ /* @__PURE__ */ import_react29.default.createElement(
2257
+ Toggle,
2258
+ {
2259
+ name: "bank-transaction-display",
2260
+ options: [
2261
+ { label: "To Review", value: "review" /* review */ },
2262
+ { label: "Categorized", value: "categorized" /* categorized */ }
2263
+ ],
2264
+ selected: display,
2265
+ onChange: onCategorizationDisplayChange
2266
+ }
2267
+ )
2268
+ ), /* @__PURE__ */ import_react29.default.createElement(
2269
+ "table",
2270
+ {
2271
+ width: "100%",
2272
+ className: "Layer__table Layer__bank-transactions__table"
2273
+ },
2274
+ /* @__PURE__ */ import_react29.default.createElement("thead", null, /* @__PURE__ */ import_react29.default.createElement("tr", null, /* @__PURE__ */ import_react29.default.createElement("th", { className: "Layer__table-header Layer__bank-transactions__date-col" }, "Date"), /* @__PURE__ */ import_react29.default.createElement("th", { className: "Layer__table-header Layer__bank-transactions__tx-col" }, "Transaction"), /* @__PURE__ */ import_react29.default.createElement("th", { className: "Layer__table-header Layer__bank-transactions__account-col" }, "Account"), /* @__PURE__ */ import_react29.default.createElement("th", { className: "Layer__table-header Layer__table-cell--amount Layer__table-cell__amount-col" }, "Amount"), editable ? /* @__PURE__ */ import_react29.default.createElement("th", { className: "Layer__table-header Layer__table-header--primary Layer__table-cell__category-col" }, "Categorize") : /* @__PURE__ */ import_react29.default.createElement("th", { className: "Layer__table-header Layer__table-cell__category-col" }, "Category"))),
2275
+ /* @__PURE__ */ import_react29.default.createElement("tbody", null, !isLoading && bankTransactions.map((bankTransaction) => /* @__PURE__ */ import_react29.default.createElement(
2276
+ BankTransactionRow,
2277
+ {
2278
+ key: bankTransaction.id,
2279
+ dateFormat,
2280
+ bankTransaction,
2281
+ isOpen: openRows[bankTransaction.id],
2282
+ toggleOpen,
2283
+ editable
2284
+ }
2285
+ )))
2286
+ ), isLoading || !bankTransactions || bankTransactions?.length === 0 ? /* @__PURE__ */ import_react29.default.createElement(Loader2, null) : null, !isLoading && /* @__PURE__ */ import_react29.default.createElement("ul", { className: "Layer__bank-transactions__list" }, bankTransactions.map((bankTransaction) => /* @__PURE__ */ import_react29.default.createElement(
2287
+ BankTransactionListItem,
1043
2288
  {
1044
2289
  key: bankTransaction.id,
1045
2290
  dateFormat,
1046
2291
  bankTransaction,
1047
2292
  isOpen: openRows[bankTransaction.id],
1048
2293
  toggleOpen,
1049
- editable: display === "review" /* review */
2294
+ editable
1050
2295
  }
1051
2296
  ))));
1052
2297
  };
1053
2298
 
1054
2299
  // src/components/Hello/Hello.tsx
1055
- var import_react13 = __toESM(require("react"));
2300
+ var import_react30 = __toESM(require("react"));
1056
2301
  var import_swr3 = __toESM(require("swr"));
1057
2302
  var fetcher = (url) => fetch(url).then((res) => res.json());
1058
2303
  var Hello = ({ user }) => {
@@ -1061,26 +2306,26 @@ var Hello = ({ user }) => {
1061
2306
  fetcher
1062
2307
  );
1063
2308
  const name = (isLoading ? "..." : data?.name) || "User";
1064
- return /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement("div", { className: "hello" }, "Hello, ", name, "!"));
2309
+ return /* @__PURE__ */ import_react30.default.createElement(import_react30.default.Fragment, null, /* @__PURE__ */ import_react30.default.createElement("div", { className: "hello" }, "Hello, ", name, "!"));
1065
2310
  };
1066
2311
 
1067
2312
  // src/components/ProfitAndLoss/ProfitAndLoss.tsx
1068
- var import_react21 = __toESM(require("react"));
2313
+ var import_react38 = __toESM(require("react"));
1069
2314
 
1070
2315
  // src/hooks/useProfitAndLoss/useProfitAndLoss.tsx
1071
- var import_react14 = require("react");
1072
- var import_date_fns5 = require("date-fns");
2316
+ var import_react31 = require("react");
2317
+ var import_date_fns6 = require("date-fns");
1073
2318
  var import_swr4 = __toESM(require("swr"));
1074
2319
  var useProfitAndLoss = ({ startDate: initialStartDate, endDate: initialEndDate } = {
1075
- startDate: (0, import_date_fns5.startOfMonth)(/* @__PURE__ */ new Date()),
1076
- endDate: (0, import_date_fns5.endOfMonth)(/* @__PURE__ */ new Date())
2320
+ startDate: (0, import_date_fns6.startOfMonth)(/* @__PURE__ */ new Date()),
2321
+ endDate: (0, import_date_fns6.endOfMonth)(/* @__PURE__ */ new Date())
1077
2322
  }) => {
1078
- const { auth, businessId } = useLayerContext();
1079
- const [startDate, setStartDate] = (0, import_react14.useState)(
1080
- initialStartDate || (0, import_date_fns5.startOfMonth)(Date.now())
2323
+ const { auth, businessId, apiUrl } = useLayerContext();
2324
+ const [startDate, setStartDate] = (0, import_react31.useState)(
2325
+ initialStartDate || (0, import_date_fns6.startOfMonth)(Date.now())
1081
2326
  );
1082
- const [endDate, setEndDate] = (0, import_react14.useState)(
1083
- initialEndDate || (0, import_date_fns5.endOfMonth)(Date.now())
2327
+ const [endDate, setEndDate] = (0, import_react31.useState)(
2328
+ initialEndDate || (0, import_date_fns6.endOfMonth)(Date.now())
1084
2329
  );
1085
2330
  const {
1086
2331
  data: rawData,
@@ -1088,11 +2333,11 @@ var useProfitAndLoss = ({ startDate: initialStartDate, endDate: initialEndDate }
1088
2333
  error: rawError
1089
2334
  } = (0, import_swr4.default)(
1090
2335
  businessId && startDate && endDate && auth?.access_token && `profit-and-loss-${businessId}-${startDate.valueOf()}-${endDate.valueOf()}`,
1091
- Layer.getProfitAndLoss(auth?.access_token, {
2336
+ Layer.getProfitAndLoss(apiUrl, auth?.access_token, {
1092
2337
  params: {
1093
2338
  businessId,
1094
- startDate: (0, import_date_fns5.formatISO)(startDate),
1095
- endDate: (0, import_date_fns5.formatISO)(endDate)
2339
+ startDate: (0, import_date_fns6.formatISO)(startDate),
2340
+ endDate: (0, import_date_fns6.formatISO)(endDate)
1096
2341
  }
1097
2342
  })
1098
2343
  );
@@ -1114,10 +2359,10 @@ var useProfitAndLoss = ({ startDate: initialStartDate, endDate: initialEndDate }
1114
2359
  };
1115
2360
 
1116
2361
  // src/components/ProfitAndLossChart/ProfitAndLossChart.tsx
1117
- var import_react16 = __toESM(require("react"));
2362
+ var import_react33 = __toESM(require("react"));
1118
2363
 
1119
2364
  // src/components/ProfitAndLossChart/Indicator.tsx
1120
- var import_react15 = __toESM(require("react"));
2365
+ var import_react32 = __toESM(require("react"));
1121
2366
  var emptyViewBox = { x: 0, y: 0, width: 0, height: 0 };
1122
2367
  var Indicator = ({
1123
2368
  viewBox = {},
@@ -1137,16 +2382,17 @@ var Indicator = ({
1137
2382
  const boxWidth = width * 2 + 4;
1138
2383
  const multiplier = 1.5;
1139
2384
  const xOffset = (boxWidth * multiplier - boxWidth) / 2;
1140
- (0, import_react15.useEffect)(() => {
2385
+ (0, import_react32.useEffect)(() => {
1141
2386
  setAnimateFrom(animateTo);
1142
2387
  }, [animateTo]);
1143
2388
  const actualX = animateFrom === -1 ? animateTo : animateFrom;
1144
- return /* @__PURE__ */ import_react15.default.createElement(
2389
+ return /* @__PURE__ */ import_react32.default.createElement(
1145
2390
  "rect",
1146
2391
  {
1147
2392
  className: "Layer__profit-and-loss-chart__selection-indicator",
1148
2393
  style: {
1149
2394
  width: `${boxWidth * multiplier}px`,
2395
+ // @ts-expect-error -- y is fine but x apparently isn't!
1150
2396
  x: actualX - xOffset,
1151
2397
  y: y + height
1152
2398
  }
@@ -1155,106 +2401,106 @@ var Indicator = ({
1155
2401
  };
1156
2402
 
1157
2403
  // src/components/ProfitAndLossChart/ProfitAndLossChart.tsx
1158
- var import_date_fns6 = require("date-fns");
2404
+ var import_date_fns7 = require("date-fns");
1159
2405
  var import_recharts = require("recharts");
1160
2406
  var barGap = 4;
1161
2407
  var barSize = 20;
1162
2408
  var ProfitAndLossChart = () => {
1163
- const { changeDateRange, dateRange } = (0, import_react16.useContext)(ProfitAndLoss.Context);
1164
- const thisMonth = (0, import_date_fns6.startOfMonth)(Date.now());
2409
+ const { changeDateRange, dateRange } = (0, import_react33.useContext)(ProfitAndLoss.Context);
2410
+ const thisMonth = (0, import_date_fns7.startOfMonth)(Date.now());
1165
2411
  const startSelectionMonth = dateRange.startDate.getMonth();
1166
2412
  const endSelectionMonth = dateRange.endDate.getMonth();
1167
2413
  const monthData = [];
1168
2414
  monthData.push(
1169
2415
  useProfitAndLoss({
1170
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 11 })),
1171
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 11 }))
2416
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 11 })),
2417
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 11 }))
1172
2418
  })?.data
1173
2419
  );
1174
2420
  monthData.push(
1175
2421
  useProfitAndLoss({
1176
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 10 })),
1177
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 10 }))
2422
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 10 })),
2423
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 10 }))
1178
2424
  })?.data
1179
2425
  );
1180
2426
  monthData.push(
1181
2427
  useProfitAndLoss({
1182
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 9 })),
1183
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 9 }))
2428
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 9 })),
2429
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 9 }))
1184
2430
  })?.data
1185
2431
  );
1186
2432
  monthData.push(
1187
2433
  useProfitAndLoss({
1188
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 8 })),
1189
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 8 }))
2434
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 8 })),
2435
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 8 }))
1190
2436
  })?.data
1191
2437
  );
1192
2438
  monthData.push(
1193
2439
  useProfitAndLoss({
1194
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 7 })),
1195
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 7 }))
2440
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 7 })),
2441
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 7 }))
1196
2442
  })?.data
1197
2443
  );
1198
2444
  monthData.push(
1199
2445
  useProfitAndLoss({
1200
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 6 })),
1201
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 6 }))
2446
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 6 })),
2447
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 6 }))
1202
2448
  })?.data
1203
2449
  );
1204
2450
  monthData.push(
1205
2451
  useProfitAndLoss({
1206
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 5 })),
1207
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 5 }))
2452
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 5 })),
2453
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 5 }))
1208
2454
  })?.data
1209
2455
  );
1210
2456
  monthData.push(
1211
2457
  useProfitAndLoss({
1212
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 4 })),
1213
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 4 }))
2458
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 4 })),
2459
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 4 }))
1214
2460
  })?.data
1215
2461
  );
1216
2462
  monthData.push(
1217
2463
  useProfitAndLoss({
1218
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 3 })),
1219
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 3 }))
2464
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 3 })),
2465
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 3 }))
1220
2466
  })?.data
1221
2467
  );
1222
2468
  monthData.push(
1223
2469
  useProfitAndLoss({
1224
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 2 })),
1225
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 2 }))
2470
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 2 })),
2471
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 2 }))
1226
2472
  })?.data
1227
2473
  );
1228
2474
  monthData.push(
1229
2475
  useProfitAndLoss({
1230
- startDate: (0, import_date_fns6.startOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 1 })),
1231
- endDate: (0, import_date_fns6.endOfMonth)((0, import_date_fns6.sub)(thisMonth, { months: 1 }))
2476
+ startDate: (0, import_date_fns7.startOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 1 })),
2477
+ endDate: (0, import_date_fns7.endOfMonth)((0, import_date_fns7.sub)(thisMonth, { months: 1 }))
1232
2478
  })?.data
1233
2479
  );
1234
2480
  monthData.push(
1235
2481
  useProfitAndLoss({
1236
2482
  startDate: thisMonth,
1237
- endDate: (0, import_date_fns6.endOfMonth)(thisMonth)
2483
+ endDate: (0, import_date_fns7.endOfMonth)(thisMonth)
1238
2484
  })?.data
1239
2485
  );
1240
- const getMonthName = (pnl) => !!pnl ? (0, import_date_fns6.format)((0, import_date_fns6.parseISO)(pnl.start_date), "LLL") : "";
2486
+ const getMonthName = (pnl) => pnl ? (0, import_date_fns7.format)((0, import_date_fns7.parseISO)(pnl.start_date), "LLL") : "";
1241
2487
  const summarizePnL = (pnl) => ({
1242
2488
  name: getMonthName(pnl),
1243
2489
  revenue: pnl?.income.value || 0,
1244
2490
  expenses: (pnl?.income.value || 0) - (pnl?.net_profit || 0),
1245
- selected: !!pnl && (0, import_date_fns6.parseISO)(pnl.start_date).getMonth() >= startSelectionMonth && (0, import_date_fns6.parseISO)(pnl.end_date).getMonth() <= endSelectionMonth
2491
+ selected: !!pnl && (0, import_date_fns7.parseISO)(pnl.start_date).getMonth() >= startSelectionMonth && (0, import_date_fns7.parseISO)(pnl.end_date).getMonth() <= endSelectionMonth
1246
2492
  });
1247
2493
  const onClick = ({ activeTooltipIndex }) => {
1248
2494
  const selection = monthData[activeTooltipIndex || -1];
1249
2495
  if (selection) {
1250
2496
  const { start_date: startDate, end_date: endDate } = selection;
1251
2497
  changeDateRange({
1252
- startDate: (0, import_date_fns6.parseISO)(startDate),
1253
- endDate: (0, import_date_fns6.parseISO)(endDate)
2498
+ startDate: (0, import_date_fns7.parseISO)(startDate),
2499
+ endDate: (0, import_date_fns7.parseISO)(endDate)
1254
2500
  });
1255
2501
  }
1256
2502
  };
1257
- const data = (0, import_react16.useMemo)(
2503
+ const data = (0, import_react33.useMemo)(
1258
2504
  () => monthData.map(summarizePnL),
1259
2505
  [
1260
2506
  startSelectionMonth,
@@ -1262,8 +2508,8 @@ var ProfitAndLossChart = () => {
1262
2508
  ...monthData.map((m) => m?.net_profit)
1263
2509
  ]
1264
2510
  );
1265
- const [animateFrom, setAnimateFrom] = (0, import_react16.useState)(-1);
1266
- return /* @__PURE__ */ import_react16.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: 250 }, /* @__PURE__ */ import_react16.default.createElement(
2511
+ const [animateFrom, setAnimateFrom] = (0, import_react33.useState)(-1);
2512
+ return /* @__PURE__ */ import_react33.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: 250 }, /* @__PURE__ */ import_react33.default.createElement(
1267
2513
  import_recharts.BarChart,
1268
2514
  {
1269
2515
  margin: { left: 24, right: 24, bottom: 24 },
@@ -1272,8 +2518,8 @@ var ProfitAndLossChart = () => {
1272
2518
  barGap,
1273
2519
  className: "Layer__profit-and-loss-chart"
1274
2520
  },
1275
- /* @__PURE__ */ import_react16.default.createElement(import_recharts.CartesianGrid, { vertical: false }),
1276
- /* @__PURE__ */ import_react16.default.createElement(
2521
+ /* @__PURE__ */ import_react33.default.createElement(import_recharts.CartesianGrid, { vertical: false }),
2522
+ /* @__PURE__ */ import_react33.default.createElement(
1277
2523
  import_recharts.Legend,
1278
2524
  {
1279
2525
  verticalAlign: "top",
@@ -1284,8 +2530,8 @@ var ProfitAndLossChart = () => {
1284
2530
  ]
1285
2531
  }
1286
2532
  ),
1287
- /* @__PURE__ */ import_react16.default.createElement(import_recharts.XAxis, { dataKey: "name", tickLine: false }),
1288
- /* @__PURE__ */ import_react16.default.createElement(
2533
+ /* @__PURE__ */ import_react33.default.createElement(import_recharts.XAxis, { dataKey: "name", tickLine: false }),
2534
+ /* @__PURE__ */ import_react33.default.createElement(
1289
2535
  import_recharts.Bar,
1290
2536
  {
1291
2537
  dataKey: "revenue",
@@ -1294,10 +2540,10 @@ var ProfitAndLossChart = () => {
1294
2540
  radius: [barSize / 4, barSize / 4, 0, 0],
1295
2541
  className: "Layer__profit-and-loss-chart__bar--income"
1296
2542
  },
1297
- /* @__PURE__ */ import_react16.default.createElement(
2543
+ /* @__PURE__ */ import_react33.default.createElement(
1298
2544
  import_recharts.LabelList,
1299
2545
  {
1300
- content: /* @__PURE__ */ import_react16.default.createElement(
2546
+ content: /* @__PURE__ */ import_react33.default.createElement(
1301
2547
  Indicator,
1302
2548
  {
1303
2549
  animateFrom,
@@ -1306,7 +2552,7 @@ var ProfitAndLossChart = () => {
1306
2552
  )
1307
2553
  }
1308
2554
  ),
1309
- data.map((entry) => /* @__PURE__ */ import_react16.default.createElement(
2555
+ data.map((entry) => /* @__PURE__ */ import_react33.default.createElement(
1310
2556
  import_recharts.Cell,
1311
2557
  {
1312
2558
  key: entry.name,
@@ -1314,7 +2560,7 @@ var ProfitAndLossChart = () => {
1314
2560
  }
1315
2561
  ))
1316
2562
  ),
1317
- /* @__PURE__ */ import_react16.default.createElement(
2563
+ /* @__PURE__ */ import_react33.default.createElement(
1318
2564
  import_recharts.Bar,
1319
2565
  {
1320
2566
  dataKey: "expenses",
@@ -1323,7 +2569,7 @@ var ProfitAndLossChart = () => {
1323
2569
  radius: [barSize / 4, barSize / 4, 0, 0],
1324
2570
  className: "Layer__profit-and-loss-chart__bar--expenses"
1325
2571
  },
1326
- data.map((entry) => /* @__PURE__ */ import_react16.default.createElement(
2572
+ data.map((entry) => /* @__PURE__ */ import_react33.default.createElement(
1327
2573
  import_recharts.Cell,
1328
2574
  {
1329
2575
  key: entry.name,
@@ -1335,15 +2581,15 @@ var ProfitAndLossChart = () => {
1335
2581
  };
1336
2582
 
1337
2583
  // src/components/ProfitAndLossDatePicker/ProfitAndLossDatePicker.tsx
1338
- var import_react17 = __toESM(require("react"));
2584
+ var import_react34 = __toESM(require("react"));
1339
2585
 
1340
2586
  // src/icons/ChevronLeft.tsx
1341
- var React22 = __toESM(require("react"));
2587
+ var React40 = __toESM(require("react"));
1342
2588
  var ChevronLeft = ({
1343
2589
  strokeColor,
1344
2590
  size,
1345
2591
  ...props
1346
- }) => /* @__PURE__ */ React22.createElement(
2592
+ }) => /* @__PURE__ */ React40.createElement(
1347
2593
  "svg",
1348
2594
  {
1349
2595
  xmlns: "http://www.w3.org/2000/svg",
@@ -1353,7 +2599,7 @@ var ChevronLeft = ({
1353
2599
  viewBox: "0 0 24 24",
1354
2600
  ...props
1355
2601
  },
1356
- /* @__PURE__ */ React22.createElement(
2602
+ /* @__PURE__ */ React40.createElement(
1357
2603
  "path",
1358
2604
  {
1359
2605
  stroke: strokeColor ?? "#000",
@@ -1366,43 +2612,68 @@ var ChevronLeft = ({
1366
2612
  );
1367
2613
  var ChevronLeft_default = ChevronLeft;
1368
2614
 
2615
+ // src/icons/ChevronRight.tsx
2616
+ var React41 = __toESM(require("react"));
2617
+ var ChavronRight = ({ size, ...props }) => /* @__PURE__ */ React41.createElement(
2618
+ "svg",
2619
+ {
2620
+ xmlns: "http://www.w3.org/2000/svg",
2621
+ width: size || 24,
2622
+ height: size || 24,
2623
+ fill: "none",
2624
+ viewBox: "0 0 24 24",
2625
+ ...props
2626
+ },
2627
+ /* @__PURE__ */ React41.createElement(
2628
+ "path",
2629
+ {
2630
+ stroke: "#000",
2631
+ strokeLinecap: "round",
2632
+ strokeLinejoin: "round",
2633
+ strokeWidth: 2,
2634
+ d: "m9 18 6-6-6-6"
2635
+ }
2636
+ )
2637
+ );
2638
+ var ChevronRight_default = ChavronRight;
2639
+
1369
2640
  // src/components/ProfitAndLossDatePicker/ProfitAndLossDatePicker.tsx
1370
- var import_date_fns7 = require("date-fns");
2641
+ var import_date_fns8 = require("date-fns");
1371
2642
  var ProfitAndLossDatePicker = () => {
1372
- const { changeDateRange, dateRange } = (0, import_react17.useContext)(ProfitAndLoss.Context);
2643
+ const { changeDateRange, dateRange } = (0, import_react34.useContext)(ProfitAndLoss.Context);
1373
2644
  const date = dateRange.startDate;
1374
- const label = (0, import_date_fns7.format)(date, "LLLL y");
2645
+ const label = (0, import_date_fns8.format)(date, "LLLL y");
1375
2646
  const change = (duration) => {
1376
- const newDate = (0, import_date_fns7.add)(date, duration);
2647
+ const newDate = (0, import_date_fns8.add)(date, duration);
1377
2648
  changeDateRange({
1378
- startDate: (0, import_date_fns7.startOfMonth)(newDate),
1379
- endDate: (0, import_date_fns7.endOfMonth)(newDate)
2649
+ startDate: (0, import_date_fns8.startOfMonth)(newDate),
2650
+ endDate: (0, import_date_fns8.endOfMonth)(newDate)
1380
2651
  });
1381
2652
  };
1382
2653
  const previousMonth = () => change({ months: -1 });
1383
2654
  const nextMonth = () => change({ months: 1 });
1384
- return /* @__PURE__ */ import_react17.default.createElement("div", { className: "Layer__profit-and-loss-date-picker" }, /* @__PURE__ */ import_react17.default.createElement(
2655
+ return /* @__PURE__ */ import_react34.default.createElement("div", { className: "Layer__profit-and-loss-date-picker" }, /* @__PURE__ */ import_react34.default.createElement(
1385
2656
  "button",
1386
2657
  {
1387
2658
  "aria-label": "View Previous Month",
1388
2659
  className: "Layer__profit-and-loss-date-picker__button",
1389
2660
  onClick: previousMonth
1390
2661
  },
1391
- /* @__PURE__ */ import_react17.default.createElement(
2662
+ /* @__PURE__ */ import_react34.default.createElement(
1392
2663
  ChevronLeft_default,
1393
2664
  {
1394
2665
  className: "Layer__profit-and-loss-date-picker__button-icon",
1395
2666
  size: 18
1396
2667
  }
1397
2668
  )
1398
- ), /* @__PURE__ */ import_react17.default.createElement("span", { className: "Layer__profit-and-loss-date-picker__label" }, label), /* @__PURE__ */ import_react17.default.createElement(
2669
+ ), /* @__PURE__ */ import_react34.default.createElement("span", { className: "Layer__profit-and-loss-date-picker__label" }, label), /* @__PURE__ */ import_react34.default.createElement(
1399
2670
  "button",
1400
2671
  {
1401
2672
  "aria-label": "View Next Month",
1402
2673
  className: "Layer__profit-and-loss-date-picker__button",
1403
2674
  onClick: nextMonth
1404
2675
  },
1405
- /* @__PURE__ */ import_react17.default.createElement(
2676
+ /* @__PURE__ */ import_react34.default.createElement(
1406
2677
  ChevronRight_default,
1407
2678
  {
1408
2679
  className: "Layer__profit-and-loss-date-picker__button-icon",
@@ -1413,35 +2684,53 @@ var ProfitAndLossDatePicker = () => {
1413
2684
  };
1414
2685
 
1415
2686
  // src/components/ProfitAndLossSummaries/ProfitAndLossSummaries.tsx
1416
- var import_react18 = __toESM(require("react"));
1417
- var import_date_fns8 = require("date-fns");
2687
+ var import_react35 = __toESM(require("react"));
1418
2688
  var ProfitAndLossSummaries = () => {
1419
- const { data } = (0, import_react18.useContext)(ProfitAndLoss.Context);
1420
- if (!data) {
1421
- return null;
1422
- }
1423
- const monthName = (0, import_date_fns8.format)((0, import_date_fns8.parseISO)(data?.start_date), "LLLL");
1424
- return /* @__PURE__ */ import_react18.default.createElement("div", { className: "Layer__profit-and-loss-summaries" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "Layer__profit-and-loss-summaries__summary Layer__profit-and-loss-summaries__summary--income" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Revenue"), /* @__PURE__ */ import_react18.default.createElement("span", { className: "Layer__profit-and-loss-summaries__amount" }, centsToDollars(data.income.value))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "Layer__profit-and-loss-summaries__summary Layer__profit-and-loss-summaries__summary--expenses" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Expenses"), /* @__PURE__ */ import_react18.default.createElement("span", { className: "Layer__profit-and-loss-summaries__amount" }, centsToDollars(Math.abs(data.income.value - data.net_profit)))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "Layer__profit-and-loss-summaries__summary Layer__profit-and-loss-summaries__summary--net-profit" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Net Profit"), /* @__PURE__ */ import_react18.default.createElement("span", { className: "Layer__profit-and-loss-summaries__amount" }, centsToDollars(data.net_profit))));
2689
+ const { data: storedData } = (0, import_react35.useContext)(ProfitAndLoss.Context);
2690
+ const data = storedData ? storedData : { income: { value: NaN }, net_profit: NaN };
2691
+ const incomeDirectionClass = (data.income.value ?? NaN) < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--pasitive";
2692
+ const expensesDirectionClass = (data?.income?.value ?? NaN) - data.net_profit < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--pasitive";
2693
+ const netProfitDirectionClass = data.net_profit < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--pasitive";
2694
+ return /* @__PURE__ */ import_react35.default.createElement("div", { className: "Layer__profit-and-loss-summaries" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "Layer__profit-and-loss-summaries__summary Layer__profit-and-loss-summaries__summary--income" }, /* @__PURE__ */ import_react35.default.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Revenue"), /* @__PURE__ */ import_react35.default.createElement(
2695
+ "span",
2696
+ {
2697
+ className: `Layer__profit-and-loss-summaries__amount ${incomeDirectionClass}`
2698
+ },
2699
+ centsToDollars(Math.abs(data?.income?.value ?? NaN))
2700
+ )), /* @__PURE__ */ import_react35.default.createElement("div", { className: "Layer__profit-and-loss-summaries__summary Layer__profit-and-loss-summaries__summary--expenses" }, /* @__PURE__ */ import_react35.default.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Expenses"), /* @__PURE__ */ import_react35.default.createElement(
2701
+ "span",
2702
+ {
2703
+ className: `Layer__profit-and-loss-summaries__amount ${expensesDirectionClass}`
2704
+ },
2705
+ centsToDollars(Math.abs((data.income.value ?? 0) - data.net_profit))
2706
+ )), /* @__PURE__ */ import_react35.default.createElement("div", { className: "Layer__profit-and-loss-summaries__summary Layer__profit-and-loss-summaries__summary--net-profit" }, /* @__PURE__ */ import_react35.default.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Net Profit"), /* @__PURE__ */ import_react35.default.createElement(
2707
+ "span",
2708
+ {
2709
+ className: `Layer__profit-and-loss-summaries__amount ${netProfitDirectionClass}`
2710
+ },
2711
+ centsToDollars(Math.abs(data.net_profit))
2712
+ )));
1425
2713
  };
1426
2714
 
1427
2715
  // src/components/ProfitAndLossTable/ProfitAndLossTable.tsx
1428
- var import_react20 = __toESM(require("react"));
2716
+ var import_react37 = __toESM(require("react"));
1429
2717
 
1430
2718
  // src/components/ProfitAndLossRow/ProfitAndLossRow.tsx
1431
- var import_react19 = __toESM(require("react"));
2719
+ var import_react36 = __toESM(require("react"));
1432
2720
  var ProfitAndLossRow = ({
1433
2721
  variant,
1434
2722
  lineItem,
1435
2723
  depth = 0,
1436
2724
  maxDepth = 1,
1437
- direction = "DEBIT" /* DEBIT */
2725
+ direction = "DEBIT" /* DEBIT */,
2726
+ summarize = true
1438
2727
  }) => {
1439
2728
  if (!lineItem) {
1440
2729
  return null;
1441
2730
  }
1442
- const { value, display_name, line_items, name } = lineItem;
1443
- const variantName = variant || name;
1444
- const amount = value || 0;
2731
+ const { value, display_name, line_items } = lineItem;
2732
+ const [expanded, setExpanded] = (0, import_react36.useState)(true);
2733
+ const amount = value ?? 0;
1445
2734
  const amountString = centsToDollars(Math.abs(amount));
1446
2735
  const labelClasses = [
1447
2736
  "Layer__profit-and-loss-row",
@@ -1451,87 +2740,154 @@ var ProfitAndLossRow = ({
1451
2740
  "Layer__profit-and-loss-row",
1452
2741
  "Layer__profit-and-loss-row__value"
1453
2742
  ];
2743
+ const positive = amount === 0 || direction === "CREDIT" /* CREDIT */ && amount > 0 || direction === "DEBIT" /* DEBIT */ && amount < 0;
1454
2744
  valueClasses.push(
1455
- direction === "CREDIT" /* CREDIT */ ? "Layer__profit-and-loss-row__value--amount-positive" : "Layer__profit-and-loss-row__value--amount-negative"
2745
+ positive ? "Layer__profit-and-loss-row__value--amount-positive" : "Layer__profit-and-loss-row__value--amount-negative"
1456
2746
  );
1457
2747
  labelClasses.push(`Layer__profit-and-loss-row__label--depth-${depth}`);
1458
2748
  valueClasses.push(`Layer__profit-and-loss-row__value--depth-${depth}`);
1459
- variantName && labelClasses.push(
1460
- `Layer__profit-and-loss-row__label--variant-${variantName}`
2749
+ variant && labelClasses.push(`Layer__profit-and-loss-row__label--variant-${variant}`);
2750
+ variant && valueClasses.push(`Layer__profit-and-loss-row__value--variant-${variant}`);
2751
+ const toggleExpanded = () => setExpanded(!expanded);
2752
+ const canGoDeeper = depth < maxDepth;
2753
+ const hasChildren = (line_items?.length ?? 0) > 0;
2754
+ const displayChildren = hasChildren && canGoDeeper;
2755
+ labelClasses.push(
2756
+ `Layer__profit-and-loss-row__label--display-children-${displayChildren}`
1461
2757
  );
1462
- variantName && valueClasses.push(
1463
- `Layer__profit-and-loss-row__value--variant-${variantName}`
2758
+ valueClasses.push(
2759
+ `Layer__profit-and-loss-row__value--display-children-${displayChildren}`
1464
2760
  );
1465
- return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("div", { className: labelClasses.join(" ") }, display_name), /* @__PURE__ */ import_react19.default.createElement("div", { className: valueClasses.join(" ") }, amountString), depth < maxDepth && (line_items || []).map((line_item) => /* @__PURE__ */ import_react19.default.createElement(
1466
- ProfitAndLossRow,
2761
+ displayChildren && expanded && labelClasses.push("Layer__profit-and-loss-row__label--expanded");
2762
+ displayChildren && expanded && valueClasses.push("Layer__profit-and-loss-row__value--expanded");
2763
+ return /* @__PURE__ */ import_react36.default.createElement(import_react36.default.Fragment, null, /* @__PURE__ */ import_react36.default.createElement("div", { className: labelClasses.join(" "), onClick: toggleExpanded }, /* @__PURE__ */ import_react36.default.createElement(ChevronDown_default, { size: 16 }), display_name), /* @__PURE__ */ import_react36.default.createElement("div", { className: valueClasses.join(" ") }, amountString), canGoDeeper && hasChildren && /* @__PURE__ */ import_react36.default.createElement(
2764
+ "div",
1467
2765
  {
1468
- key: line_item.display_name,
1469
- lineItem: line_item,
1470
- depth: depth + 1,
1471
- maxDepth,
1472
- direction
1473
- }
1474
- )));
2766
+ className: `Layer__profit-and-loss-row__children ${expanded && "Layer__profit-and-loss-row__children--expanded"}`
2767
+ },
2768
+ /* @__PURE__ */ import_react36.default.createElement("div", { className: "Layer__balance-sheet-row__children--content" }, (line_items || []).map((line_item) => /* @__PURE__ */ import_react36.default.createElement(
2769
+ ProfitAndLossRow,
2770
+ {
2771
+ key: line_item.display_name,
2772
+ lineItem: line_item,
2773
+ depth: depth + 1,
2774
+ maxDepth,
2775
+ direction
2776
+ }
2777
+ )), summarize && /* @__PURE__ */ import_react36.default.createElement(
2778
+ ProfitAndLossRow,
2779
+ {
2780
+ key: display_name,
2781
+ lineItem: { value, display_name: `Total of ${display_name}` },
2782
+ variant: "summation",
2783
+ depth: depth + 1,
2784
+ maxDepth
2785
+ }
2786
+ ))
2787
+ ));
2788
+ };
2789
+
2790
+ // src/components/ProfitAndLossTable/empty_profit_and_loss_report.ts
2791
+ var empty_profit_and_loss_report_default = {
2792
+ type: "Profit_And_Loss",
2793
+ business_id: "",
2794
+ start_date: "",
2795
+ end_date: "",
2796
+ income: {
2797
+ name: "INCOME",
2798
+ display_name: "Income",
2799
+ value: NaN,
2800
+ line_items: null
2801
+ },
2802
+ cost_of_goods_sold: {
2803
+ display_name: "Cost of Goods Sold",
2804
+ name: "COGS",
2805
+ value: NaN,
2806
+ line_items: null
2807
+ },
2808
+ gross_profit: NaN,
2809
+ expenses: {
2810
+ name: "EXPENSES",
2811
+ display_name: "Expenses",
2812
+ value: NaN,
2813
+ line_items: null
2814
+ },
2815
+ profit_before_taxes: NaN,
2816
+ taxes: {
2817
+ name: "TAXES",
2818
+ display_name: "Taxes",
2819
+ value: NaN,
2820
+ line_items: null
2821
+ },
2822
+ net_profit: NaN,
2823
+ other_outflows: {
2824
+ name: "OTHER_OUTFLOWS",
2825
+ display_name: "Other outflows",
2826
+ value: NaN,
2827
+ line_items: null
2828
+ },
2829
+ personal_expenses: {
2830
+ name: "PERSONAL",
2831
+ display_name: "Personal expenses",
2832
+ value: NaN,
2833
+ line_items: null
2834
+ },
2835
+ fully_categorized: false
1475
2836
  };
1476
2837
 
1477
2838
  // src/components/ProfitAndLossTable/ProfitAndLossTable.tsx
1478
2839
  var ProfitAndLossTable = () => {
1479
- const { data, isLoading } = (0, import_react20.useContext)(ProfitAndLoss.Context);
1480
- return /* @__PURE__ */ import_react20.default.createElement("div", { className: "Layer__profit-and-loss-table" }, !data || isLoading ? /* @__PURE__ */ import_react20.default.createElement("div", null, "Loading") : /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
1481
- ProfitAndLossRow,
1482
- {
1483
- lineItem: data.income,
1484
- direction: "CREDIT" /* CREDIT */
1485
- }
1486
- ), /* @__PURE__ */ import_react20.default.createElement(
2840
+ const { data: actualData, isLoading } = (0, import_react37.useContext)(ProfitAndLoss.Context);
2841
+ const data = !actualData || isLoading ? empty_profit_and_loss_report_default : actualData;
2842
+ return /* @__PURE__ */ import_react37.default.createElement(import_react37.default.Fragment, null, /* @__PURE__ */ import_react37.default.createElement("div", { className: "Layer__profit-and-loss-table" }, /* @__PURE__ */ import_react37.default.createElement(ProfitAndLossRow, { lineItem: data.income, direction: "CREDIT" /* CREDIT */ }), /* @__PURE__ */ import_react37.default.createElement(
1487
2843
  ProfitAndLossRow,
1488
2844
  {
1489
2845
  lineItem: data.cost_of_goods_sold,
1490
2846
  direction: "DEBIT" /* DEBIT */
1491
2847
  }
1492
- ), /* @__PURE__ */ import_react20.default.createElement(
2848
+ ), /* @__PURE__ */ import_react37.default.createElement(
1493
2849
  ProfitAndLossRow,
1494
2850
  {
1495
2851
  lineItem: {
1496
2852
  value: data.gross_profit,
1497
2853
  display_name: "Gross Profit"
1498
2854
  },
1499
- variant: "GROSS",
2855
+ variant: "summation",
1500
2856
  direction: "CREDIT" /* CREDIT */
1501
2857
  }
1502
- ), /* @__PURE__ */ import_react20.default.createElement(
2858
+ ), /* @__PURE__ */ import_react37.default.createElement(
1503
2859
  ProfitAndLossRow,
1504
2860
  {
1505
2861
  lineItem: data.expenses,
1506
2862
  direction: "DEBIT" /* DEBIT */
1507
2863
  }
1508
- ), /* @__PURE__ */ import_react20.default.createElement(
2864
+ ), /* @__PURE__ */ import_react37.default.createElement(
1509
2865
  ProfitAndLossRow,
1510
2866
  {
1511
2867
  lineItem: {
1512
2868
  value: data.profit_before_taxes,
1513
2869
  display_name: "Profit Before Taxes"
1514
2870
  },
1515
- variant: "BEFORETAX",
2871
+ variant: "summation",
1516
2872
  direction: "CREDIT" /* CREDIT */
1517
2873
  }
1518
- ), /* @__PURE__ */ import_react20.default.createElement(ProfitAndLossRow, { lineItem: data.taxes, direction: "DEBIT" /* DEBIT */ }), /* @__PURE__ */ import_react20.default.createElement(
2874
+ ), /* @__PURE__ */ import_react37.default.createElement(ProfitAndLossRow, { lineItem: data.taxes, direction: "DEBIT" /* DEBIT */ }), /* @__PURE__ */ import_react37.default.createElement(
1519
2875
  ProfitAndLossRow,
1520
2876
  {
1521
2877
  lineItem: {
1522
2878
  value: data.net_profit,
1523
2879
  display_name: "Net Profit"
1524
2880
  },
1525
- variant: "NETPROFIT",
2881
+ variant: "summation",
1526
2882
  direction: "CREDIT" /* CREDIT */
1527
2883
  }
1528
- ), /* @__PURE__ */ import_react20.default.createElement(
2884
+ )), /* @__PURE__ */ import_react37.default.createElement("div", { className: "Layer__profit-and-loss-table Layer__profit-and-loss-table__outflows" }, /* @__PURE__ */ import_react37.default.createElement(
1529
2885
  ProfitAndLossRow,
1530
2886
  {
1531
2887
  lineItem: data.other_outflows,
1532
2888
  direction: "DEBIT" /* DEBIT */
1533
2889
  }
1534
- ), /* @__PURE__ */ import_react20.default.createElement(
2890
+ ), /* @__PURE__ */ import_react37.default.createElement(
1535
2891
  ProfitAndLossRow,
1536
2892
  {
1537
2893
  lineItem: data.personal_expenses,
@@ -1542,7 +2898,7 @@ var ProfitAndLossTable = () => {
1542
2898
 
1543
2899
  // src/components/ProfitAndLoss/ProfitAndLoss.tsx
1544
2900
  var import_date_fns9 = require("date-fns");
1545
- var PNLContext = (0, import_react21.createContext)({
2901
+ var PNLContext = (0, import_react38.createContext)({
1546
2902
  data: void 0,
1547
2903
  isLoading: true,
1548
2904
  error: void 0,
@@ -1555,7 +2911,7 @@ var PNLContext = (0, import_react21.createContext)({
1555
2911
  });
1556
2912
  var ProfitAndLoss = ({ children }) => {
1557
2913
  const contextData = useProfitAndLoss();
1558
- return /* @__PURE__ */ import_react21.default.createElement(PNLContext.Provider, { value: contextData }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "Layer__profit-and-loss" }, /* @__PURE__ */ import_react21.default.createElement("h2", { className: "Layer__profit-and-loss__title" }, "Profit & Loss"), children));
2914
+ return /* @__PURE__ */ import_react38.default.createElement(PNLContext.Provider, { value: contextData }, /* @__PURE__ */ import_react38.default.createElement("div", { className: "Layer__component Layer__profit-and-loss" }, /* @__PURE__ */ import_react38.default.createElement("h2", { className: "Layer__profit-and-loss__title" }, "Profit & Loss"), children));
1559
2915
  };
1560
2916
  ProfitAndLoss.Chart = ProfitAndLossChart;
1561
2917
  ProfitAndLoss.Context = PNLContext;
@@ -1564,12 +2920,14 @@ ProfitAndLoss.Summaries = ProfitAndLossSummaries;
1564
2920
  ProfitAndLoss.Table = ProfitAndLossTable;
1565
2921
 
1566
2922
  // src/providers/LayerProvider/LayerProvider.tsx
1567
- var import_react22 = __toESM(require("react"));
2923
+ var import_react39 = __toESM(require("react"));
2924
+ var import_date_fns10 = require("date-fns");
1568
2925
  var import_swr5 = __toESM(require("swr"));
1569
2926
  var reducer = (state, action) => {
1570
2927
  switch (action.type) {
1571
2928
  case "LayerContext.setAuth" /* setAuth */:
1572
2929
  case "LayerContext.setCategories" /* setCategories */:
2930
+ case "LayerContext.setTheme" /* setTheme */:
1573
2931
  return { ...state, ...action.payload };
1574
2932
  default:
1575
2933
  return state;
@@ -1578,11 +2936,13 @@ var reducer = (state, action) => {
1578
2936
  var LayerEnvironment = {
1579
2937
  production: {
1580
2938
  url: "not defined yet",
1581
- scope: "not defined yet"
2939
+ scope: "not defined yet",
2940
+ apiUrl: "not defined yet"
1582
2941
  },
1583
2942
  staging: {
1584
2943
  url: "https://auth.layerfi.com/oauth2/token",
1585
- scope: "https://sandbox.layerfi.com/sandbox"
2944
+ scope: "https://sandbox.layerfi.com/sandbox",
2945
+ apiUrl: "https://sandbox.layerfi.com"
1586
2946
  }
1587
2947
  };
1588
2948
  var LayerProvider = ({
@@ -1590,8 +2950,9 @@ var LayerProvider = ({
1590
2950
  appSecret,
1591
2951
  businessId,
1592
2952
  children,
1593
- clientId,
1594
- environment = "production"
2953
+ businessAccessToken,
2954
+ environment = "production",
2955
+ theme
1595
2956
  }) => {
1596
2957
  const defaultSWRConfig = {
1597
2958
  revalidateInterval: 0,
@@ -1599,47 +2960,234 @@ var LayerProvider = ({
1599
2960
  revalidateOnReconnect: false,
1600
2961
  revalidateIfStale: false
1601
2962
  };
1602
- const { url, scope } = LayerEnvironment[environment];
1603
- const [state, dispatch] = (0, import_react22.useReducer)(reducer, {
1604
- auth: { access_token: "", token_type: "", expires_in: 0 },
2963
+ const { url, scope, apiUrl } = LayerEnvironment[environment];
2964
+ const [state, dispatch] = (0, import_react39.useReducer)(reducer, {
2965
+ auth: {
2966
+ access_token: "",
2967
+ token_type: "",
2968
+ expires_in: 0,
2969
+ expires_at: new Date(2e3, 1, 1)
2970
+ },
1605
2971
  businessId,
1606
- categories: []
2972
+ categories: [],
2973
+ apiUrl,
2974
+ theme
1607
2975
  });
1608
- const { data: auth } = (0, import_swr5.default)(
1609
- "authenticate",
2976
+ const { data: auth } = appId !== void 0 && appSecret !== void 0 ? (0, import_swr5.default)(
2977
+ businessAccessToken === void 0 && appId !== void 0 && appSecret !== void 0 && (0, import_date_fns10.isBefore)(state.auth.expires_at, /* @__PURE__ */ new Date()) && "authenticate",
1610
2978
  Layer.authenticate({
1611
2979
  appId,
1612
2980
  appSecret,
1613
2981
  authenticationUrl: url,
1614
- scope,
1615
- clientId
2982
+ scope
1616
2983
  }),
1617
2984
  defaultSWRConfig
1618
- );
1619
- (0, import_react22.useEffect)(() => {
1620
- if (!!auth?.access_token) {
1621
- dispatch({ type: "LayerContext.setAuth" /* setAuth */, payload: { auth } });
2985
+ ) : { data: void 0 };
2986
+ (0, import_react39.useEffect)(() => {
2987
+ if (businessAccessToken) {
2988
+ dispatch({
2989
+ type: "LayerContext.setAuth" /* setAuth */,
2990
+ payload: {
2991
+ auth: {
2992
+ access_token: businessAccessToken,
2993
+ token_type: "Bearer",
2994
+ expires_in: 3600,
2995
+ expires_at: (0, import_date_fns10.add)(/* @__PURE__ */ new Date(), { seconds: 3600 })
2996
+ }
2997
+ }
2998
+ });
2999
+ } else if (auth?.access_token) {
3000
+ dispatch({
3001
+ type: "LayerContext.setAuth" /* setAuth */,
3002
+ payload: {
3003
+ auth: {
3004
+ ...auth,
3005
+ expires_at: (0, import_date_fns10.add)(/* @__PURE__ */ new Date(), { seconds: auth.expires_in })
3006
+ }
3007
+ }
3008
+ });
1622
3009
  }
1623
- }, [auth?.access_token]);
3010
+ }, [businessAccessToken, auth?.access_token]);
1624
3011
  const { data: categories } = (0, import_swr5.default)(
1625
3012
  businessId && auth?.access_token && `categories-${businessId}`,
1626
- Layer.getCategories(auth?.access_token, { params: { businessId } }),
3013
+ Layer.getCategories(apiUrl, auth?.access_token, { params: { businessId } }),
1627
3014
  defaultSWRConfig
1628
3015
  );
1629
- (0, import_react22.useEffect)(() => {
1630
- if (!!categories?.data?.categories?.length) {
3016
+ (0, import_react39.useEffect)(() => {
3017
+ if (categories?.data?.categories?.length) {
1631
3018
  dispatch({
1632
3019
  type: "LayerContext.setCategories" /* setCategories */,
1633
3020
  payload: { categories: categories.data.categories || [] }
1634
3021
  });
1635
3022
  }
1636
3023
  }, [categories?.data?.categories?.length]);
1637
- return /* @__PURE__ */ import_react22.default.createElement(import_swr5.SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ import_react22.default.createElement(LayerContext.Provider, { value: state }, children));
3024
+ const setTheme = (theme2) => dispatch({
3025
+ type: "LayerContext.setTheme" /* setTheme */,
3026
+ payload: { theme: theme2 }
3027
+ });
3028
+ return /* @__PURE__ */ import_react39.default.createElement(import_swr5.SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ import_react39.default.createElement(LayerContext.Provider, { value: { ...state, setTheme } }, children));
3029
+ };
3030
+
3031
+ // src/components/ChartOfAccounts/ChartOfAccounts.tsx
3032
+ var import_react42 = __toESM(require("react"));
3033
+
3034
+ // src/hooks/useChartOfAccounts/useChartOfAccounts.tsx
3035
+ var import_swr6 = __toESM(require("swr"));
3036
+ var useChartOfAccounts = () => {
3037
+ const { auth, businessId, apiUrl } = useLayerContext();
3038
+ const { data, isLoading, error, mutate } = (0, import_swr6.default)(
3039
+ businessId && auth?.access_token && `chart-of-accounts-${businessId}`,
3040
+ Layer.getChartOfAccounts(apiUrl, auth?.access_token, {
3041
+ params: { businessId }
3042
+ })
3043
+ );
3044
+ const create = (newAccount) => Layer.createAccount(apiUrl, auth?.access_token, {
3045
+ params: { businessId },
3046
+ body: newAccount
3047
+ }).then(({ data: data2 }) => (mutate(), data2));
3048
+ return { data: data?.data, isLoading, error, create };
3049
+ };
3050
+
3051
+ // src/components/ChartOfAccountsNewForm/ChartOfAccountsNewForm.tsx
3052
+ var import_react40 = __toESM(require("react"));
3053
+ var import_react_select2 = __toESM(require("react-select"));
3054
+ var flattenAccounts = (accounts) => accounts.flatMap((a) => [a, flattenAccounts(a.subAccounts || [])]).flat().filter((id) => id);
3055
+ var ChartOfAccountsNewForm = () => {
3056
+ const { data, create: createAccount2 } = useChartOfAccounts();
3057
+ const accountOptions = (0, import_react40.useMemo)(
3058
+ () => flattenAccounts(data?.accounts || []).sort(
3059
+ (a, b) => a?.name && b?.name ? a.name.localeCompare(b.name) : 0
3060
+ ),
3061
+ [data?.accounts?.length]
3062
+ );
3063
+ const [name, setName] = (0, import_react40.useState)("");
3064
+ const [description, setDescription] = (0, import_react40.useState)("");
3065
+ const [normality, setNormality] = (0, import_react40.useState)("DEBIT" /* DEBIT */);
3066
+ const [parentAccount, setParentAccount] = (0, import_react40.useState)(
3067
+ data?.accounts[0]
3068
+ );
3069
+ const save = () => {
3070
+ createAccount2({
3071
+ name,
3072
+ normality,
3073
+ parent_id: {
3074
+ type: "AccountId",
3075
+ id: parentAccount?.id || ""
3076
+ },
3077
+ description
3078
+ });
3079
+ };
3080
+ return /* @__PURE__ */ import_react40.default.createElement("div", { className: "Layer__chart-of-accounts-new-form" }, /* @__PURE__ */ import_react40.default.createElement("div", { className: "Layer__chart-of-accounts-new-form__field" }, /* @__PURE__ */ import_react40.default.createElement("span", null, "Name"), /* @__PURE__ */ import_react40.default.createElement(
3081
+ "input",
3082
+ {
3083
+ name: "name",
3084
+ value: name,
3085
+ onChange: (event) => setName(event.target.value)
3086
+ }
3087
+ )), /* @__PURE__ */ import_react40.default.createElement("div", { className: "Layer__chart-of-accounts-new-form__field" }, /* @__PURE__ */ import_react40.default.createElement("span", null, "Description"), /* @__PURE__ */ import_react40.default.createElement(
3088
+ "input",
3089
+ {
3090
+ name: "description",
3091
+ value: description,
3092
+ onChange: (event) => setDescription(event.target.value)
3093
+ }
3094
+ )), /* @__PURE__ */ import_react40.default.createElement("div", { className: "Layer__chart-of-accounts-new-form__field" }, /* @__PURE__ */ import_react40.default.createElement("span", null, "Normality"), /* @__PURE__ */ import_react40.default.createElement(
3095
+ import_react_select2.default,
3096
+ {
3097
+ isSearchable: false,
3098
+ onChange: (value) => value && setNormality(value.value),
3099
+ options: [
3100
+ { label: "Credit", value: "CREDIT" /* CREDIT */ },
3101
+ { label: "Debit", value: "DEBIT" /* DEBIT */ }
3102
+ ]
3103
+ }
3104
+ )), /* @__PURE__ */ import_react40.default.createElement("div", { className: "Layer__chart-of-accounts-new-form__field" }, /* @__PURE__ */ import_react40.default.createElement("span", null, "Parent Account"), /* @__PURE__ */ import_react40.default.createElement(
3105
+ import_react_select2.default,
3106
+ {
3107
+ isSearchable: true,
3108
+ value: parentAccount,
3109
+ onChange: (value) => value && setParentAccount(value),
3110
+ getOptionLabel: (a) => a.name,
3111
+ getOptionValue: (a) => a.id,
3112
+ options: accountOptions
3113
+ }
3114
+ )), /* @__PURE__ */ import_react40.default.createElement("div", { className: "Layer__chart-of-accounts-new-form__field Layer__chart-of-accounts-new-form__field--actions" }, /* @__PURE__ */ import_react40.default.createElement("button", { onClick: save }, "Save")));
3115
+ };
3116
+
3117
+ // src/components/ChartOfAccountsRow/ChartOfAccountsRow.tsx
3118
+ var import_react41 = __toESM(require("react"));
3119
+ var ChartOfAccountsRow = ({ account, depth = 0 }) => {
3120
+ const classNames12 = [
3121
+ "Layer__chart-of-accounts-row__table-cell",
3122
+ depth > 0 && `Layer__chart-of-accounts-row__table-cell--depth-${depth}`
3123
+ ];
3124
+ const className = classNames12.filter((id) => id).join(" ");
3125
+ const amountClassName = account.balance < 0 ? "Layer__chart-of-accounts-row__table-cell--amount-negative" : "Layer__chart-of-accounts-row__table-cell--amount-positive";
3126
+ return /* @__PURE__ */ import_react41.default.createElement(import_react41.default.Fragment, null, /* @__PURE__ */ import_react41.default.createElement(
3127
+ "div",
3128
+ {
3129
+ className: `${className} Layer__chart-of-accounts-row__table-cell--name`
3130
+ },
3131
+ account.name
3132
+ ), /* @__PURE__ */ import_react41.default.createElement(
3133
+ "div",
3134
+ {
3135
+ className: `${className} Layer__chart-of-accounts-row__table-cell--type`
3136
+ },
3137
+ "Assets"
3138
+ ), /* @__PURE__ */ import_react41.default.createElement(
3139
+ "div",
3140
+ {
3141
+ className: `${className} Layer__chart-of-accounts-row__table-cell--subtype`
3142
+ },
3143
+ "Cash"
3144
+ ), /* @__PURE__ */ import_react41.default.createElement(
3145
+ "div",
3146
+ {
3147
+ className: `${className} Layer__chart-of-accounts-row__table-cell--balance ${amountClassName}`
3148
+ },
3149
+ centsToDollars(Math.abs(account.balance || 0))
3150
+ ), /* @__PURE__ */ import_react41.default.createElement(
3151
+ "div",
3152
+ {
3153
+ className: `${className} Layer__chart-of-accounts-row__table-cell--actions`
3154
+ },
3155
+ /* @__PURE__ */ import_react41.default.createElement("button", { className: "Layer__chart-of-accounts-row__view-entries-button" }, "View Entries")
3156
+ ), (account.subAccounts || []).map((subAccount) => /* @__PURE__ */ import_react41.default.createElement(
3157
+ ChartOfAccountsRow,
3158
+ {
3159
+ key: subAccount.id,
3160
+ account: subAccount,
3161
+ depth: depth + 1
3162
+ }
3163
+ )));
3164
+ };
3165
+
3166
+ // src/components/ChartOfAccounts/ChartOfAccounts.tsx
3167
+ var ChartOfAccounts = () => {
3168
+ const { data, isLoading } = useChartOfAccounts();
3169
+ const [showingForm, setShowingForm] = (0, import_react42.useState)(false);
3170
+ return /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__component Layer__chart-of-accounts" }, !data || isLoading ? "Loading." : /* @__PURE__ */ import_react42.default.createElement(import_react42.default.Fragment, null, /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__header" }, /* @__PURE__ */ import_react42.default.createElement("h2", { className: "Layer__chart-of-accounts__title" }, "Chart of Accounts"), /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__actions" }, /* @__PURE__ */ import_react42.default.createElement("button", { className: "Layer__chart-of-accounts__download-button" }, /* @__PURE__ */ import_react42.default.createElement(DownloadCloud_default, null), "Download"), /* @__PURE__ */ import_react42.default.createElement(
3171
+ "button",
3172
+ {
3173
+ className: "Layer__chart-of-accounts__edit-accounts-button",
3174
+ onClick: () => setShowingForm(!showingForm)
3175
+ },
3176
+ "Edit Accounts"
3177
+ ))), showingForm && /* @__PURE__ */ import_react42.default.createElement(ChartOfAccountsNewForm, null), /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__table" }, /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__table-cell Layer__chart-of-accounts__table-cell--header" }, "Name"), /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__table-cell Layer__chart-of-accounts__table-cell--header" }, "Type"), /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__table-cell Layer__chart-of-accounts__table-cell--header" }, "Sub-Type"), /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__table-cell Layer__chart-of-accounts__table-cell--header Layer__chart-of-accounts__table-cell--header-balance" }, "Balance"), /* @__PURE__ */ import_react42.default.createElement("div", { className: "Layer__chart-of-accounts__table-cell Layer__chart-of-accounts__table-cell--header" }), data.accounts.map((account) => /* @__PURE__ */ import_react42.default.createElement(
3178
+ ChartOfAccountsRow,
3179
+ {
3180
+ key: account.id,
3181
+ account,
3182
+ depth: 0
3183
+ }
3184
+ )))));
1638
3185
  };
1639
3186
  // Annotate the CommonJS export names for ESM import in node:
1640
3187
  0 && (module.exports = {
1641
3188
  BalanceSheet,
1642
3189
  BankTransactions,
3190
+ ChartOfAccounts,
1643
3191
  Hello,
1644
3192
  LayerProvider,
1645
3193
  ProfitAndLoss