@layerfi/components 0.1.0 → 0.1.1

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