@layerfi/components 0.1.0 → 0.1.2

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