@layerfi/components 0.1.52 → 0.1.54

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
@@ -1,5 +1,5 @@
1
1
  // src/providers/LayerProvider/LayerProvider.tsx
2
- import React7, { useReducer, useEffect as useEffect3 } from "react";
2
+ import React7, { useReducer, useEffect as useEffect4 } from "react";
3
3
 
4
4
  // src/api/util.ts
5
5
  var formStringFromObject = (object) => Object.entries(object).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
@@ -148,9 +148,12 @@ var getBankTransactions = get(
148
148
  businessId,
149
149
  cursor,
150
150
  categorized,
151
+ direction,
152
+ startDate,
153
+ endDate,
151
154
  sortBy = "date",
152
155
  sortOrder = "DESC"
153
- }) => `/v1/businesses/${businessId}/bank-transactions?${cursor ? `cursor=${cursor}&` : ""}${categorized !== void 0 && categorized !== "" ? `categorized=${categorized}&` : ""}sort_by=${sortBy}&sort_order=${sortOrder}&limit=200`
156
+ }) => `/v1/businesses/${businessId}/bank-transactions?${cursor !== void 0 && cursor !== "" ? `cursor=${cursor}&` : ""}${categorized !== void 0 && categorized !== "" ? `categorized=${categorized}&` : ""}${direction !== void 0 ? `direction=${direction}&` : ""}${startDate !== void 0 && startDate !== "" ? `start_date=${startDate}&` : ""}${endDate !== void 0 && endDate !== "" ? `end_date=${endDate}&` : ""}sort_by=${sortBy}&sort_order=${sortOrder}&limit=200`
154
157
  );
155
158
  var categorizeBankTransaction = put(
156
159
  ({ businessId, bankTransactionId }) => `/v1/businesses/${businessId}/bank-transactions/${bankTransactionId}/categorize`
@@ -491,6 +494,7 @@ var LayerContext = createContext2({
491
494
  syncTimestamps: {},
492
495
  readTimestamps: {},
493
496
  hasBeenTouched: () => false,
497
+ expireDataCaches: () => void 0,
494
498
  eventCallbacks: {}
495
499
  });
496
500
  var useLayerContext = () => useContext2(LayerContext);
@@ -547,9 +551,19 @@ var DEPENDENCIES = {
547
551
  ["CHART_OF_ACCOUNTS" /* CHART_OF_ACCOUNTS */]: ALL_TOUCHABLE,
548
552
  ["JOURNAL" /* JOURNAL */]: ALL_TOUCHABLE,
549
553
  ["LEDGER_ACCOUNTS" /* LEDGER_ACCOUNTS */]: ALL_TOUCHABLE,
550
- ["LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */]: ALL_TOUCHABLE,
554
+ ["LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */]: [
555
+ "BUSINESS" /* BUSINESS */,
556
+ "LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */,
557
+ "CHART_OF_ACCOUNTS" /* CHART_OF_ACCOUNTS */
558
+ ],
551
559
  ["PROFIT_AND_LOSS" /* PROFIT_AND_LOSS */]: ALL_TOUCHABLE,
552
- ["STATEMENT_OF_CASH_FLOWS" /* STATEMENT_OF_CASH_FLOWS */]: ALL_TOUCHABLE
560
+ ["STATEMENT_OF_CASH_FLOWS" /* STATEMENT_OF_CASH_FLOWS */]: ALL_TOUCHABLE,
561
+ ["BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */]: [
562
+ "LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */,
563
+ "BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */,
564
+ "BUSINESS" /* BUSINESS */,
565
+ "CHART_OF_ACCOUNTS" /* CHART_OF_ACCOUNTS */
566
+ ]
553
567
  };
554
568
  var readTimestampsG = {};
555
569
  var useDataSync = () => {
@@ -561,7 +575,8 @@ var useDataSync = () => {
561
575
  ["LEDGER_ACCOUNTS" /* LEDGER_ACCOUNTS */]: initialTimestamp,
562
576
  ["LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */]: initialTimestamp,
563
577
  ["PROFIT_AND_LOSS" /* PROFIT_AND_LOSS */]: initialTimestamp,
564
- ["STATEMENT_OF_CASH_FLOWS" /* STATEMENT_OF_CASH_FLOWS */]: initialTimestamp
578
+ ["STATEMENT_OF_CASH_FLOWS" /* STATEMENT_OF_CASH_FLOWS */]: initialTimestamp,
579
+ ["BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */]: initialTimestamp
565
580
  });
566
581
  const [readTimestamps, setReadTimestamps] = useState2({});
567
582
  const touch = (model) => {
@@ -591,12 +606,26 @@ var useDataSync = () => {
591
606
  })
592
607
  );
593
608
  };
609
+ const resetCaches = () => {
610
+ const now = Date.now();
611
+ setSyncTimestamps({
612
+ ["BALANCE_SHEET" /* BALANCE_SHEET */]: now,
613
+ ["CHART_OF_ACCOUNTS" /* CHART_OF_ACCOUNTS */]: now,
614
+ ["JOURNAL" /* JOURNAL */]: now,
615
+ ["LEDGER_ACCOUNTS" /* LEDGER_ACCOUNTS */]: now,
616
+ ["LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */]: now,
617
+ ["PROFIT_AND_LOSS" /* PROFIT_AND_LOSS */]: now,
618
+ ["STATEMENT_OF_CASH_FLOWS" /* STATEMENT_OF_CASH_FLOWS */]: now,
619
+ ["BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */]: now
620
+ });
621
+ };
594
622
  return {
595
623
  touch,
596
624
  read,
597
625
  syncTimestamps,
598
626
  readTimestamps,
599
- hasBeenTouched
627
+ hasBeenTouched,
628
+ resetCaches
600
629
  };
601
630
  };
602
631
 
@@ -628,10 +657,10 @@ import React6 from "react";
628
657
  import { createContext as createContext3, useContext as useContext4 } from "react";
629
658
 
630
659
  // src/types/bank_transactions.ts
631
- var Direction = /* @__PURE__ */ ((Direction3) => {
632
- Direction3["CREDIT"] = "CREDIT";
633
- Direction3["DEBIT"] = "DEBIT";
634
- return Direction3;
660
+ var Direction = /* @__PURE__ */ ((Direction2) => {
661
+ Direction2["CREDIT"] = "CREDIT";
662
+ Direction2["DEBIT"] = "DEBIT";
663
+ return Direction2;
635
664
  })(Direction || {});
636
665
  var DisplayState = /* @__PURE__ */ ((DisplayState2) => {
637
666
  DisplayState2["all"] = "all";
@@ -663,6 +692,7 @@ var BankTransactionsContext = createContext3({
663
692
  pagination: void 0
664
693
  },
665
694
  updateOneLocal: () => void 0,
695
+ shouldHideAfterCategorize: () => false,
666
696
  removeAfterCategorize: () => void 0,
667
697
  activate: () => void 0,
668
698
  display: "review" /* review */,
@@ -673,1278 +703,1289 @@ var BankTransactionsContext = createContext3({
673
703
  var useBankTransactionsContext = () => useContext4(BankTransactionsContext);
674
704
 
675
705
  // src/hooks/useBankTransactions/useBankTransactions.tsx
676
- import { useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
677
-
678
- // src/components/BankTransactions/constants.ts
679
- var CategorizedCategories = [
680
- "CATEGORIZED" /* CATEGORIZED */,
681
- "JOURNALING" /* JOURNALING */,
682
- "SPLIT" /* SPLIT */,
683
- "MATCHED" /* MATCHED */
684
- ];
685
- var ReviewCategories = [
686
- "READY_FOR_INPUT" /* READY_FOR_INPUT */,
687
- "LAYER_REVIEW" /* LAYER_REVIEW */
688
- ];
706
+ import { useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState5 } from "react";
689
707
 
690
- // src/components/BankTransactions/utils.ts
691
- var filterVisibility = (scope, bankTransaction) => {
692
- const categorized = CategorizedCategories.includes(
693
- bankTransaction.categorization_status
694
- );
695
- const inReview = ReviewCategories.includes(
696
- bankTransaction.categorization_status
697
- );
698
- return scope === "all" /* all */ || scope === "review" /* review */ && inReview || scope === "categorized" /* categorized */ && categorized;
699
- };
700
- var isCategorized = (bankTransaction) => CategorizedCategories.includes(bankTransaction.categorization_status);
708
+ // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
709
+ import { useEffect as useEffect2, useState as useState4 } from "react";
710
+ import { usePlaidLink } from "react-plaid-link";
701
711
 
702
- // src/hooks/useBankTransactions/utils.ts
703
- import { parseISO } from "date-fns";
704
- var collectAccounts = (transactions) => {
705
- const accounts = [];
706
- if (!transactions) {
707
- return accounts;
708
- }
709
- transactions.forEach((x) => {
710
- if (!accounts.find((y) => y.id === x.source_account_id)) {
711
- accounts.push({
712
- id: x.source_account_id,
713
- name: x.account_name || ""
714
- });
715
- }
716
- });
717
- return accounts.sort((a, b) => a.name.localeCompare(b.name));
718
- };
719
- var applyAmountFilter = (data, filter) => {
720
- return data?.filter((x) => {
721
- if ((filter?.min || filter?.min === 0) && (filter?.max || filter?.max === 0)) {
722
- return x.amount >= filter.min * 100 && x.amount <= filter.max * 100;
723
- }
724
- if (filter?.min || filter?.min === 0) {
725
- return x.amount >= filter.min * 100;
726
- }
727
- if (filter?.max || filter?.max === 0) {
728
- return x.amount <= filter.max * 100;
729
- }
730
- });
731
- };
732
- var applyAccountFilter = (data, filter) => data?.filter((x) => filter && filter.includes(x.source_account_id));
733
- var applyDirectionFilter = (data, filter) => {
734
- if (!filter) {
735
- return data;
736
- }
737
- const normalizedFilter = filter.map((x) => x.toLowerCase());
738
- return data?.filter(
739
- (x) => normalizedFilter.includes(x.direction?.toLowerCase())
740
- );
741
- };
742
- var applyCategorizationStatusFilter = (data, filter) => {
743
- if (!filter) {
744
- return data;
712
+ // src/hooks/useLinkedAccounts/mockData.ts
713
+ var LINKED_ACCOUNTS_MOCK_DATA = [
714
+ {
715
+ id: "d800ada8-8075-4436-a712-08efabcbd51a",
716
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
717
+ external_account_source: "PLAID",
718
+ external_account_name: "Citi Double Cash\xAE Card",
719
+ mask: "1234",
720
+ latest_balance_timestamp: {
721
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
722
+ external_account_source: "PLAID",
723
+ balance: 435121,
724
+ at: "2024-04-03T13:00:00Z",
725
+ created_at: "2024-04-06T22:47:59.715458Z"
726
+ },
727
+ current_ledger_balance: 373717,
728
+ institution: {
729
+ name: "Chase",
730
+ logo: ""
731
+ },
732
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
733
+ connection_external_id: "11111",
734
+ connection_needs_repair_as_of: null,
735
+ requires_user_confirmation_as_of: null,
736
+ is_syncing: true
737
+ },
738
+ {
739
+ id: "f98ec50a-c370-484d-a35b-d00207436075",
740
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
741
+ external_account_source: "PLAID",
742
+ external_account_name: "Citi Double Cash\xAE Card",
743
+ mask: "1234",
744
+ latest_balance_timestamp: {
745
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
746
+ external_account_source: "PLAID",
747
+ balance: 435121,
748
+ at: "2024-04-03T13:00:00Z",
749
+ created_at: "2024-04-06T16:44:35.715458Z"
750
+ },
751
+ current_ledger_balance: 373717,
752
+ institution: {
753
+ name: "Chase",
754
+ logo: ""
755
+ },
756
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
757
+ connection_external_id: "11111",
758
+ connection_needs_repair_as_of: null,
759
+ requires_user_confirmation_as_of: null,
760
+ is_syncing: false
761
+ },
762
+ {
763
+ id: "843f1748-fdaa-422d-a73d-2489a40c8dc7",
764
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
765
+ external_account_source: "PLAID",
766
+ external_account_name: "Citi Double Cash\xAE Card",
767
+ mask: "1234",
768
+ latest_balance_timestamp: {
769
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
770
+ external_account_source: "PLAID",
771
+ balance: 435121,
772
+ at: "2024-04-03T13:00:00Z",
773
+ created_at: "2024-04-06T16:44:35.715458Z"
774
+ },
775
+ current_ledger_balance: 373717,
776
+ institution: {
777
+ name: "Chase",
778
+ logo: ""
779
+ },
780
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
781
+ connection_external_id: "11111",
782
+ connection_needs_repair_as_of: "2024-03-06T16:44:35.715458Z",
783
+ requires_user_confirmation_as_of: null,
784
+ is_syncing: false
785
+ },
786
+ {
787
+ id: "8f430e29-e339-4d71-a08a-fce469c7a7c1",
788
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
789
+ external_account_source: "PLAID",
790
+ external_account_name: "Citi Double Cash\xAE Card",
791
+ mask: "1234",
792
+ latest_balance_timestamp: {
793
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
794
+ external_account_source: "PLAID",
795
+ balance: 435121,
796
+ at: "2024-04-03T13:00:00Z",
797
+ created_at: "2024-04-06T16:44:35.715458Z"
798
+ },
799
+ current_ledger_balance: 373717,
800
+ institution: {
801
+ name: "Chase",
802
+ logo: ""
803
+ },
804
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
805
+ connection_external_id: "11111",
806
+ connection_needs_repair_as_of: null,
807
+ requires_user_confirmation_as_of: "2024-03-06T16:44:35.715458Z",
808
+ is_syncing: false
745
809
  }
746
- return data?.filter(
747
- (tx) => filterVisibility(filter, tx) || filter === "all" /* all */ || filter === "review" /* review */ && tx.recently_categorized || filter === "categorized" /* categorized */ && tx.recently_categorized
748
- );
749
- };
750
- var appplyDateRangeFilter = (data, filter) => {
751
- return data?.filter((x) => {
752
- const txDate = parseISO(x.date);
753
- if (filter?.startDate && filter?.endDate) {
754
- return txDate >= filter.startDate && txDate <= filter.endDate;
755
- }
756
- if (filter?.startDate) {
757
- return txDate >= filter.startDate;
758
- }
759
- if (filter?.endDate) {
760
- return txDate <= filter.endDate;
761
- }
762
- });
763
- };
810
+ ];
764
811
 
765
- // src/hooks/useBankTransactions/useBankTransactions.tsx
766
- import useSWRInfinite from "swr/infinite";
767
- var useBankTransactions = (params) => {
812
+ // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
813
+ import useSWR from "swr";
814
+ var DEBUG = true;
815
+ var USE_MOCK_RESPONSE_DATA = false;
816
+ var useLinkedAccounts = () => {
768
817
  const {
769
818
  auth,
770
819
  businessId,
771
820
  apiUrl,
772
- addToast,
821
+ usePlaidSandbox,
773
822
  touch,
774
823
  read,
775
824
  syncTimestamps,
776
- hasBeenTouched,
777
- eventCallbacks
825
+ hasBeenTouched
778
826
  } = useLayerContext();
779
- const { scope = void 0 } = params ?? {};
780
- const [filters, setTheFilters] = useState4(
781
- scope ? { categorizationStatus: scope } : void 0
782
- );
783
- const display = useMemo2(() => {
784
- if (filters?.categorizationStatus === "review" /* review */) {
785
- return "review" /* review */;
786
- } else if (filters?.categorizationStatus === "all" /* all */) {
787
- return "all" /* all */;
788
- }
789
- return "categorized" /* categorized */;
790
- }, [filters?.categorizationStatus]);
791
- const [active, setActive] = useState4(false);
827
+ const [linkToken, setLinkToken] = useState4(null);
792
828
  const [loadingStatus, setLoadingStatus] = useState4("initial");
793
- const getKey = (_index, prevData) => {
794
- if (!auth?.access_token || !active) {
795
- return [false, void 0];
796
- }
797
- if (!prevData?.meta?.pagination?.cursor) {
798
- return [
799
- businessId && auth?.access_token && `bank-transactions-${businessId}`,
800
- void 0
801
- ];
802
- }
803
- return [
804
- businessId && auth?.access_token && `bank-transactions-${businessId}-${prevData.meta.pagination.cursor}`,
805
- prevData.meta.pagination.cursor
806
- ];
807
- };
829
+ const USE_PLAID_SANDBOX = usePlaidSandbox ?? true;
830
+ const [linkMode, setLinkMode] = useState4("add");
831
+ const queryKey = businessId && auth?.access_token && `linked-accounts-${businessId}`;
808
832
  const {
809
- data: rawResponseData,
833
+ data: responseData,
810
834
  isLoading,
811
835
  isValidating,
812
836
  error: responseError,
813
- mutate,
814
- size,
815
- setSize
816
- } = useSWRInfinite(
817
- getKey,
818
- async ([query, nextCursor]) => {
819
- if (auth?.access_token) {
820
- return Layer.getBankTransactions(apiUrl, auth?.access_token, {
821
- params: {
822
- businessId,
823
- cursor: nextCursor
824
- }
825
- }).call(false);
826
- }
827
- return {};
828
- },
829
- {
830
- initialSize: 1,
831
- revalidateFirstPage: false
832
- }
837
+ mutate
838
+ } = useSWR(
839
+ queryKey,
840
+ Layer.getLinkedAccounts(apiUrl, auth?.access_token, {
841
+ params: { businessId }
842
+ })
833
843
  );
834
- const data = useMemo2(() => {
835
- if (rawResponseData && rawResponseData.length > 0) {
836
- return rawResponseData?.map((x) => x?.data).flat().filter((x) => !!x);
844
+ useEffect2(() => {
845
+ if (!isLoading && responseData?.data.external_accounts) {
846
+ setLoadingStatus("complete");
847
+ return;
837
848
  }
838
- return void 0;
839
- }, [rawResponseData]);
840
- const lastMetadata = useMemo2(() => {
841
- if (rawResponseData && rawResponseData.length > 0) {
842
- return rawResponseData[rawResponseData.length - 1].meta;
849
+ if (isLoading && loadingStatus === "initial") {
850
+ setLoadingStatus("loading");
851
+ return;
843
852
  }
844
- return void 0;
845
- }, [rawResponseData]);
846
- const hasMore = useMemo2(() => {
847
- if (rawResponseData && rawResponseData.length > 0) {
848
- const lastElement = rawResponseData[rawResponseData.length - 1];
849
- return Boolean(
850
- lastElement.meta?.pagination?.cursor && lastElement.meta?.pagination?.has_more
851
- );
853
+ if (!isLoading && loadingStatus === "loading") {
854
+ setLoadingStatus("complete");
852
855
  }
853
- return false;
854
- }, [rawResponseData]);
855
- const accountsList = useMemo2(
856
- () => data ? collectAccounts(data) : [],
857
- [data]
858
- );
859
- useEffect2(() => {
860
- if (isLoading && loadingStatus === "initial") {
861
- setLoadingStatus("loading");
862
- return;
856
+ }, [isLoading]);
857
+ const fetchPlaidLinkToken = async () => {
858
+ if (auth?.access_token) {
859
+ const linkToken2 = (await Layer.getPlaidLinkToken(apiUrl, auth.access_token, {
860
+ params: { businessId }
861
+ })).data.link_token;
862
+ setLinkMode("add");
863
+ setLinkToken(linkToken2);
863
864
  }
864
- if (!isLoading && loadingStatus === "loading") {
865
- setLoadingStatus("complete");
866
- return;
865
+ };
866
+ const fetchPlaidUpdateModeLinkToken = async (plaidItemPlaidId) => {
867
+ if (auth?.access_token) {
868
+ const linkToken2 = (await Layer.getPlaidUpdateModeLinkToken(apiUrl, auth.access_token, {
869
+ params: { businessId },
870
+ body: { plaid_item_id: plaidItemPlaidId }
871
+ })).data.link_token;
872
+ setLinkMode("update");
873
+ setLinkToken(linkToken2);
867
874
  }
868
- }, [isLoading]);
869
- const activate = () => {
870
- setActive(true);
871
875
  };
872
- const setFilters = (value) => {
873
- setTheFilters({
874
- ...filters,
875
- ...value ?? {}
876
+ const exchangePlaidPublicToken2 = async (publicToken, metadata) => {
877
+ await Layer.exchangePlaidPublicToken(apiUrl, auth?.access_token, {
878
+ params: { businessId },
879
+ body: { public_token: publicToken, institution: metadata.institution }
876
880
  });
881
+ refetchAccounts();
877
882
  };
878
- const filteredData = useMemo2(() => {
879
- let filtered = data;
880
- if (!filtered) {
881
- return;
882
- }
883
- if (filters?.amount?.min || filters?.amount?.max) {
884
- filtered = applyAmountFilter(filtered, filters.amount);
885
- }
886
- if (filters?.account) {
887
- filtered = applyAccountFilter(filtered, filters.account);
888
- }
889
- if (filters?.direction) {
890
- filtered = applyDirectionFilter(filtered, filters.direction);
883
+ const { open: plaidLinkStart, ready: plaidLinkReady } = usePlaidLink({
884
+ token: linkToken,
885
+ // If in update mode, we don't need to exchange the public token for an access token.
886
+ // The existing access token will automatically become valid again
887
+ onSuccess: async (publicToken, metadata) => {
888
+ if (linkMode == "add") {
889
+ exchangePlaidPublicToken2(publicToken, metadata);
890
+ } else {
891
+ await updateConnectionStatus2();
892
+ refetchAccounts();
893
+ setLinkMode("add");
894
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
895
+ }
896
+ },
897
+ onExit: () => setLinkMode("add"),
898
+ env: USE_PLAID_SANDBOX ? "sandbox" : void 0
899
+ });
900
+ useEffect2(() => {
901
+ if (plaidLinkReady) {
902
+ plaidLinkStart();
891
903
  }
892
- if (filters?.categorizationStatus) {
893
- filtered = applyCategorizationStatusFilter(
894
- filtered,
895
- filters.categorizationStatus
904
+ }, [plaidLinkStart, plaidLinkReady]);
905
+ const mockResponseData = {
906
+ data: LINKED_ACCOUNTS_MOCK_DATA,
907
+ meta: {},
908
+ error: void 0
909
+ };
910
+ const addConnection = (source) => {
911
+ if (source === "PLAID") {
912
+ fetchPlaidLinkToken();
913
+ } else {
914
+ console.error(
915
+ `Adding a connection with source ${source} not yet supported`
896
916
  );
897
917
  }
898
- if (filters?.dateRange?.startDate || filters?.dateRange?.endDate) {
899
- filtered = appplyDateRangeFilter(filtered, filters?.dateRange);
918
+ };
919
+ const repairConnection = async (source, connectionExternalId) => {
920
+ if (source === "PLAID") {
921
+ await fetchPlaidUpdateModeLinkToken(connectionExternalId);
922
+ } else {
923
+ console.error(
924
+ `Repairing a connection with source ${source} not yet supported`
925
+ );
900
926
  }
901
- return filtered;
902
- }, [filters, data]);
903
- const categorize = (id, newCategory, notify) => {
904
- const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
905
- if (foundBT) {
906
- updateOneLocal({ ...foundBT, processing: true, error: void 0 });
927
+ };
928
+ const removeConnection = async (source, connectionExternalId) => {
929
+ if (source === "PLAID") {
930
+ await unlinkPlaidItem2(connectionExternalId);
931
+ await refetchAccounts();
932
+ } else {
933
+ console.error(
934
+ `Removing a connection with source ${source} not yet supported`
935
+ );
907
936
  }
908
- return Layer.categorizeBankTransaction(apiUrl, auth.access_token, {
909
- params: { businessId, bankTransactionId: id },
910
- body: newCategory
911
- }).then(({ data: newBT, errors }) => {
912
- if (newBT) {
913
- newBT.recently_categorized = true;
914
- updateOneLocal(newBT);
915
- }
916
- if (errors) {
917
- console.error(errors);
918
- throw errors;
919
- }
920
- if (newBT?.recently_categorized === true && notify) {
921
- addToast({ content: "Transaction saved" });
922
- }
923
- }).catch((err) => {
924
- const newBT = data?.find(
925
- (x) => x.business_id === businessId && x.id === id
937
+ };
938
+ const unlinkAccount2 = async (source, accountId) => {
939
+ DEBUG && console.log("unlinking account");
940
+ if (source === "PLAID") {
941
+ await Layer.unlinkAccount(apiUrl, auth?.access_token, {
942
+ params: { businessId, accountId }
943
+ });
944
+ await refetchAccounts();
945
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
946
+ } else {
947
+ console.error(
948
+ `Unlinking an account with source ${source} not yet supported`
926
949
  );
927
- if (newBT) {
928
- updateOneLocal({
929
- ...newBT,
930
- error: err.message,
931
- processing: false
932
- });
933
- }
934
- }).finally(() => {
935
- touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
936
- eventCallbacks?.onTransactionCategorized?.(id);
937
- });
950
+ }
938
951
  };
939
- const match = (id, matchId, notify) => {
940
- const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
941
- if (foundBT) {
942
- updateOneLocal({ ...foundBT, processing: true, error: void 0 });
952
+ const confirmAccount = async (source, accountId) => {
953
+ DEBUG && console.log("confirming account");
954
+ if (source === "PLAID") {
955
+ await Layer.confirmConnection(apiUrl, auth?.access_token, {
956
+ params: {
957
+ businessId,
958
+ accountId
959
+ }
960
+ });
961
+ await refetchAccounts();
962
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
963
+ } else {
964
+ console.error(
965
+ `Confirming an account with source ${source} not yet supported`
966
+ );
943
967
  }
944
- return Layer.matchBankTransaction(apiUrl, auth.access_token, {
945
- params: { businessId, bankTransactionId: id },
946
- body: { match_id: matchId, type: "Confirm_Match" /* CONFIRM_MATCH */ }
947
- }).then(({ data: bt, errors }) => {
948
- const newBT = data?.find(
949
- (x) => x.business_id === businessId && x.id === id
968
+ };
969
+ const denyAccount = async (source, accountId) => {
970
+ DEBUG && console.log("confirming account");
971
+ if (source === "PLAID") {
972
+ await Layer.denyConnection(apiUrl, auth?.access_token, {
973
+ params: {
974
+ businessId,
975
+ accountId
976
+ }
977
+ });
978
+ await refetchAccounts();
979
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
980
+ } else {
981
+ console.error(
982
+ `Denying an account with source ${source} not yet supported`
950
983
  );
951
- if (newBT) {
952
- newBT.recently_categorized = true;
953
- newBT.match = bt;
954
- newBT.categorization_status = "MATCHED" /* MATCHED */;
955
- updateOneLocal(newBT);
956
- }
957
- if (errors) {
958
- console.error(errors);
959
- throw errors;
960
- }
961
- if (newBT?.recently_categorized === true && notify) {
962
- addToast({ content: "Transaction saved" });
963
- }
964
- }).catch((err) => {
965
- const newBT = data?.find(
966
- (x) => x.business_id === businessId && x.id === id
984
+ }
985
+ };
986
+ const breakConnection = async (source, connectionExternalId) => {
987
+ DEBUG && console.log("Breaking sandbox plaid item connection");
988
+ if (source === "PLAID") {
989
+ await Layer.breakPlaidItemConnection(apiUrl, auth?.access_token, {
990
+ params: {
991
+ businessId,
992
+ plaidItemPlaidId: connectionExternalId
993
+ }
994
+ });
995
+ await refetchAccounts();
996
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
997
+ } else {
998
+ console.error(
999
+ `Breaking a sandbox connection with source ${source} not yet supported`
967
1000
  );
968
- if (newBT) {
969
- updateOneLocal({
970
- ...newBT,
971
- error: err.message,
972
- processing: false
973
- });
974
- }
975
- }).finally(() => {
976
- touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
977
- eventCallbacks?.onTransactionCategorized?.(id);
1001
+ }
1002
+ };
1003
+ const refetchAccounts = async () => {
1004
+ DEBUG && console.log("refetching accounts...");
1005
+ await mutate();
1006
+ };
1007
+ const syncAccounts = async () => {
1008
+ DEBUG && console.log("resyncing accounts...");
1009
+ await Layer.syncConnection(apiUrl, auth?.access_token, {
1010
+ params: { businessId }
978
1011
  });
979
1012
  };
980
- const updateOneLocal = (newBankTransaction) => {
981
- const updatedData = rawResponseData?.map((page) => {
982
- return {
983
- ...page,
984
- data: page.data?.map(
985
- (bt) => bt.id === newBankTransaction.id ? newBankTransaction : bt
986
- )
987
- };
1013
+ const updateConnectionStatus2 = async () => {
1014
+ DEBUG && console.log("updating connection status...");
1015
+ await Layer.updateConnectionStatus(apiUrl, auth?.access_token, {
1016
+ params: { businessId }
988
1017
  });
989
- mutate(updatedData, { revalidate: false });
990
1018
  };
991
- const removeAfterCategorize = (bankTransaction) => {
992
- };
993
- const refetch = () => {
994
- mutate();
995
- };
996
- const fetchMore = () => {
997
- if (hasMore) {
998
- setSize(size + 1);
999
- }
1019
+ const unlinkPlaidItem2 = async (plaidItemPlaidId) => {
1020
+ DEBUG && console.log("unlinking plaid item");
1021
+ await Layer.unlinkPlaidItem(apiUrl, auth?.access_token, {
1022
+ params: { businessId, plaidItemPlaidId }
1023
+ });
1024
+ await refetchAccounts();
1025
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1000
1026
  };
1001
1027
  useEffect2(() => {
1002
- if (isLoading || isValidating) {
1003
- read("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */, "bank-transactions");
1028
+ if (queryKey && (isLoading || isValidating)) {
1029
+ read("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */, queryKey);
1004
1030
  }
1005
1031
  }, [isLoading, isValidating]);
1006
1032
  useEffect2(() => {
1007
- if (hasBeenTouched("bank-transactions")) {
1008
- refetch();
1033
+ if (queryKey && hasBeenTouched(queryKey)) {
1034
+ refetchAccounts();
1009
1035
  }
1010
1036
  }, [syncTimestamps]);
1011
1037
  return {
1012
- data: filteredData,
1013
- metadata: lastMetadata,
1014
- loadingStatus,
1038
+ data: USE_MOCK_RESPONSE_DATA ? mockResponseData.data : responseData?.data.external_accounts,
1015
1039
  isLoading,
1040
+ loadingStatus,
1016
1041
  isValidating,
1017
- refetch,
1018
1042
  error: responseError,
1019
- categorize,
1020
- match,
1021
- updateOneLocal,
1022
- removeAfterCategorize,
1023
- filters,
1024
- setFilters,
1025
- accountsList,
1026
- activate,
1027
- display,
1028
- fetchMore,
1029
- hasMore
1043
+ addConnection,
1044
+ removeConnection,
1045
+ repairConnection,
1046
+ refetchAccounts,
1047
+ unlinkAccount: unlinkAccount2,
1048
+ confirmAccount,
1049
+ denyAccount,
1050
+ breakConnection,
1051
+ syncAccounts,
1052
+ updateConnectionStatus: updateConnectionStatus2
1030
1053
  };
1031
1054
  };
1032
1055
 
1033
- // src/providers/BankTransactionsProvider/BankTransactionsProvider.tsx
1034
- var BankTransactionsProvider = ({
1035
- children
1036
- }) => {
1037
- const bankTransactionsContextData = useBankTransactions();
1038
- return /* @__PURE__ */ React6.createElement(BankTransactionsContext.Provider, { value: bankTransactionsContextData }, children);
1039
- };
1040
-
1041
- // src/config/theme.ts
1042
- var SHADES = {
1043
- 50: { s: 1, l: 98 },
1044
- 100: { s: 1, l: 96 },
1045
- 200: { s: 1, l: 94 },
1046
- 300: { s: 2, l: 92 },
1047
- 500: { s: 5, l: 53 },
1048
- 600: { s: 7, l: 40 },
1049
- 700: { s: 9, l: 27 },
1050
- 800: { s: 12, l: 20 },
1051
- 1e3: { s: 20, l: 7 }
1052
- };
1053
- var COLORS = {
1054
- dark: {
1055
- h: 0,
1056
- s: 0,
1057
- l: 7
1058
- },
1059
- light: {
1060
- h: 0,
1061
- s: 0,
1062
- l: 100
1063
- }
1064
- };
1065
-
1066
- // src/utils/colors.ts
1067
- var parseStylesFromThemeConfig = (theme) => {
1068
- let styles = {};
1069
- if (!theme) {
1070
- return styles;
1071
- }
1072
- if (theme.colors) {
1073
- const darkColor = parseColorFromTheme("dark", theme.colors.dark);
1074
- const lightColor = parseColorFromTheme("light", theme.colors.light);
1075
- const textColor = parseTextColorFromTheme(theme.colors.text);
1076
- styles = { ...styles, ...darkColor, ...lightColor, ...textColor };
1077
- }
1078
- return styles;
1079
- };
1080
- var parseTextColorFromTheme = (color) => {
1081
- if (!color) {
1082
- return {};
1056
+ // src/hooks/useBankTransactions/utils.ts
1057
+ var collectAccounts = (transactions) => {
1058
+ const accounts = [];
1059
+ if (!transactions) {
1060
+ return accounts;
1083
1061
  }
1084
- try {
1085
- if ("hex" in color) {
1086
- return { "--text-color-primary": color.hex };
1062
+ transactions.forEach((x) => {
1063
+ if (!accounts.find((y) => y.id === x.source_account_id)) {
1064
+ accounts.push({
1065
+ id: x.source_account_id,
1066
+ name: x.account_name || ""
1067
+ });
1087
1068
  }
1088
- return {};
1089
- } catch (_err) {
1090
- return {};
1091
- }
1069
+ });
1070
+ return accounts.sort((a, b) => a.name.localeCompare(b.name));
1092
1071
  };
1093
- var parseColorFromTheme = (colorName, color) => {
1094
- if (!color) {
1095
- return {};
1096
- }
1097
- try {
1098
- if ("h" in color && "s" in color && "l" in color) {
1099
- return {
1100
- [`--color-${colorName}-h`]: color.h,
1101
- [`--color-${colorName}-s`]: color.s,
1102
- [`--color-${colorName}-l`]: color.l
1103
- };
1072
+ var applyAmountFilter = (data, filter) => {
1073
+ return data?.filter((x) => {
1074
+ if ((filter?.min || filter?.min === 0) && (filter?.max || filter?.max === 0)) {
1075
+ return x.amount >= filter.min * 100 && x.amount <= filter.max * 100;
1104
1076
  }
1105
- if ("r" in color && "g" in color && "b" in color) {
1106
- const { h, s, l } = rgbToHsl(color);
1107
- return {
1108
- [`--color-${colorName}-h`]: h,
1109
- [`--color-${colorName}-s`]: `${s}%`,
1110
- [`--color-${colorName}-l`]: `${l}%`
1111
- };
1077
+ if (filter?.min || filter?.min === 0) {
1078
+ return x.amount >= filter.min * 100;
1112
1079
  }
1113
- if ("hex" in color) {
1114
- const rgb = hexToRgb(color.hex);
1115
- if (!rgb) {
1116
- return {};
1117
- }
1118
- const { h, s, l } = rgbToHsl({
1119
- r: rgb.r.toString(),
1120
- g: rgb.g.toString(),
1121
- b: rgb.b.toString()
1122
- });
1123
- return {
1124
- [`--color-${colorName}-h`]: h,
1125
- [`--color-${colorName}-s`]: `${s}%`,
1126
- [`--color-${colorName}-l`]: `${l}%`
1127
- };
1080
+ if (filter?.max || filter?.max === 0) {
1081
+ return x.amount <= filter.max * 100;
1128
1082
  }
1129
- return {};
1130
- } catch (_err) {
1131
- return {};
1132
- }
1083
+ });
1133
1084
  };
1134
- var parseColorFromThemeToHsl = (color) => {
1135
- if (!color) {
1136
- return;
1137
- }
1138
- try {
1139
- if ("h" in color && "s" in color && "l" in color) {
1140
- return {
1141
- h: Number(color.h),
1142
- s: Number(color.s),
1143
- l: Number(color.l)
1144
- };
1085
+ var applyAccountFilter = (data, filter) => data?.filter((x) => filter && filter.includes(x.source_account_id));
1086
+
1087
+ // src/hooks/useBankTransactions/useBankTransactions.tsx
1088
+ import useSWRInfinite from "swr/infinite";
1089
+ var INITIAL_POLL_INTERVAL_MS = 1e3;
1090
+ var POLL_INTERVAL_AFTER_TXNS_RECEIVED_MS = 5e3;
1091
+ function useTriggerOnChange(data, anyAccountSyncing, callback) {
1092
+ const prevDataRef = useRef();
1093
+ useEffect3(() => {
1094
+ if (anyAccountSyncing && prevDataRef.current !== void 0 && prevDataRef.current !== data) {
1095
+ callback(data);
1145
1096
  }
1146
- if ("r" in color && "g" in color && "b" in color) {
1147
- const { h, s, l } = rgbToHsl(color);
1148
- return {
1149
- h,
1150
- s,
1151
- l
1152
- };
1097
+ prevDataRef.current = data;
1098
+ }, [data, anyAccountSyncing, callback]);
1099
+ }
1100
+ var filtersSettingString = (filters) => {
1101
+ return `bank-transactions${filters?.categorizationStatus ? `-categorizationStatus-${filters.categorizationStatus}` : `-categorizationStatus-${"all" /* all */}`}${filters?.direction?.length === 1 ? `-direction-${filters.direction.join("-")}` : ""}${filters?.dateRange?.startDate ? `-startDate-${filters.dateRange.startDate.toISOString()}` : ""}${filters?.dateRange?.endDate ? `-endDate-${filters.dateRange.endDate.toISOString()}` : ""}`;
1102
+ };
1103
+ var useBankTransactions = (params) => {
1104
+ const {
1105
+ auth,
1106
+ businessId,
1107
+ apiUrl,
1108
+ addToast,
1109
+ touch,
1110
+ read,
1111
+ syncTimestamps,
1112
+ hasBeenTouched,
1113
+ eventCallbacks
1114
+ } = useLayerContext();
1115
+ const { scope = void 0 } = params ?? {};
1116
+ const [filters, setTheFilters] = useState5(
1117
+ scope ? { categorizationStatus: scope } : void 0
1118
+ );
1119
+ const display = useMemo2(() => {
1120
+ if (filters?.categorizationStatus === "review" /* review */) {
1121
+ return "review" /* review */;
1122
+ } else if (filters?.categorizationStatus === "all" /* all */) {
1123
+ return "all" /* all */;
1153
1124
  }
1154
- if ("hex" in color) {
1155
- const rgb = hexToRgb(color.hex);
1156
- if (!rgb) {
1157
- return void 0;
1158
- }
1159
- const { h, s, l } = rgbToHsl({
1160
- r: rgb.r.toString(),
1161
- g: rgb.g.toString(),
1162
- b: rgb.b.toString()
1163
- });
1164
- return {
1165
- h,
1166
- s,
1167
- l
1168
- };
1125
+ return "categorized" /* categorized */;
1126
+ }, [filters?.categorizationStatus]);
1127
+ const [active, setActive] = useState5(false);
1128
+ const [loadingStatus, setLoadingStatus] = useState5("initial");
1129
+ const getKey = (index, prevData) => {
1130
+ if (!auth?.access_token || !active) {
1131
+ return [false, void 0];
1169
1132
  }
1170
- return;
1171
- } catch (_err) {
1172
- return;
1173
- }
1174
- };
1175
- var rgbToHsl = (color) => {
1176
- let r = Number(color.r);
1177
- let g = Number(color.g);
1178
- let b = Number(color.b);
1179
- r /= 255;
1180
- g /= 255;
1181
- b /= 255;
1182
- const l = Math.max(r, g, b);
1183
- const s = l - Math.min(r, g, b);
1184
- const h = s ? l === r ? (g - b) / s : l === g ? 2 + (b - r) / s : 4 + (r - g) / s : 0;
1185
- return {
1186
- h: 60 * h < 0 ? 60 * h + 360 : 60 * h,
1187
- s: 100 * (s ? l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s)) : 0),
1188
- l: 100 * (2 * l - s) / 2
1133
+ if (index === 0) {
1134
+ return [
1135
+ businessId && auth?.access_token && `${filtersSettingString(filters)}-${businessId}`,
1136
+ void 0
1137
+ ];
1138
+ }
1139
+ return [
1140
+ businessId && auth?.access_token && `${filtersSettingString(filters)}-${businessId}-${prevData?.meta?.pagination?.cursor}`,
1141
+ prevData?.meta?.pagination?.cursor.toString()
1142
+ ];
1189
1143
  };
1190
- };
1191
- var hexToRgb = (hex) => {
1192
- const values = hex.replace(
1193
- /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
1194
- (m, r, g, b) => "#" + r + r + g + g + b + b
1195
- ).substring(1).match(/.{2}/g)?.map((x) => parseInt(x, 16));
1196
- if (!values) {
1197
- return;
1198
- }
1199
- return {
1200
- r: values[0],
1201
- g: values[1],
1202
- b: values[2]
1203
- };
1204
- };
1205
- var buildColorsPalette = (theme) => {
1206
- const darkColor = parseColorFromThemeToHsl(theme?.colors?.dark) ?? COLORS.dark;
1207
- const lightColor = parseColorFromThemeToHsl(theme?.colors?.light) ?? COLORS.light;
1208
- return {
1209
- 50: buildColorShade(50, darkColor),
1210
- 100: buildColorShade(100, darkColor),
1211
- 200: buildColorShade(200, darkColor),
1212
- 300: buildColorShade(300, darkColor),
1213
- 400: {
1214
- hsl: lightColor,
1215
- rgb: hslToRgb(lightColor),
1216
- hex: hslToHex(lightColor)
1217
- },
1218
- 500: buildColorShade(500, darkColor),
1219
- 600: buildColorShade(600, darkColor),
1220
- 700: buildColorShade(700, darkColor),
1221
- 800: buildColorShade(800, darkColor),
1222
- 900: {
1223
- hsl: darkColor,
1224
- rgb: hslToRgb(darkColor),
1225
- hex: hslToHex(darkColor)
1144
+ const {
1145
+ data: rawResponseData,
1146
+ isLoading,
1147
+ isValidating,
1148
+ error: responseError,
1149
+ mutate,
1150
+ size,
1151
+ setSize
1152
+ } = useSWRInfinite(
1153
+ getKey,
1154
+ async ([_query, nextCursor]) => {
1155
+ if (auth?.access_token) {
1156
+ return Layer.getBankTransactions(apiUrl, auth?.access_token, {
1157
+ params: {
1158
+ businessId,
1159
+ cursor: nextCursor ?? "",
1160
+ categorized: filters?.categorizationStatus ? filters?.categorizationStatus === "categorized" /* categorized */ ? "true" : filters?.categorizationStatus === "review" /* review */ ? "false" : "" : "",
1161
+ direction: filters?.direction?.length === 1 ? filters.direction[0] === "CREDIT" /* CREDIT */ ? "INFLOW" : "OUTFLOW" : void 0,
1162
+ startDate: filters?.dateRange?.startDate?.toISOString() ?? void 0,
1163
+ endDate: filters?.dateRange?.endDate?.toISOString() ?? void 0
1164
+ }
1165
+ }).call(false);
1166
+ }
1167
+ return {};
1226
1168
  },
1227
- 1e3: buildColorShade(1e3, darkColor)
1169
+ {
1170
+ initialSize: 1,
1171
+ revalidateFirstPage: false
1172
+ }
1173
+ );
1174
+ const data = useMemo2(() => {
1175
+ if (rawResponseData && rawResponseData.length > 0) {
1176
+ return rawResponseData?.map((x) => x?.data).flat().filter((x) => !!x);
1177
+ }
1178
+ return void 0;
1179
+ }, [rawResponseData]);
1180
+ const lastMetadata = useMemo2(() => {
1181
+ if (rawResponseData && rawResponseData.length > 0) {
1182
+ return rawResponseData[rawResponseData.length - 1].meta;
1183
+ }
1184
+ return void 0;
1185
+ }, [rawResponseData]);
1186
+ const hasMore = useMemo2(() => {
1187
+ if (rawResponseData && rawResponseData.length > 0) {
1188
+ const lastElement = rawResponseData[rawResponseData.length - 1];
1189
+ return Boolean(
1190
+ lastElement.meta?.pagination?.cursor && lastElement.meta?.pagination?.has_more
1191
+ );
1192
+ }
1193
+ return false;
1194
+ }, [rawResponseData]);
1195
+ const accountsList = useMemo2(
1196
+ () => data ? collectAccounts(data) : [],
1197
+ [data]
1198
+ );
1199
+ useEffect3(() => {
1200
+ if (isLoading && loadingStatus === "initial") {
1201
+ setLoadingStatus("loading");
1202
+ return;
1203
+ }
1204
+ if (!isLoading && loadingStatus === "loading") {
1205
+ setLoadingStatus("complete");
1206
+ return;
1207
+ }
1208
+ }, [isLoading]);
1209
+ const activate = () => {
1210
+ setActive(true);
1228
1211
  };
1229
- };
1230
- var buildColorShade = (shade, darkColorHsl) => {
1231
- const hsl = { h: darkColorHsl.h, ...SHADES[shade] };
1232
- const rgb = hslToRgb(hsl);
1233
- const hex = hslToHex(hsl);
1234
- return { hsl, rgb, hex };
1235
- };
1236
- var hueToRgb = (p, q, t) => {
1237
- if (t < 0)
1238
- t += 1;
1239
- if (t > 1)
1240
- t -= 1;
1241
- if (t < 1 / 6)
1242
- return p + (q - p) * 6 * t;
1243
- if (t < 1 / 2)
1244
- return q;
1245
- if (t < 2 / 3)
1246
- return p + (q - p) * (2 / 3 - t) * 6;
1247
- return p;
1248
- };
1249
- var hslToRgb = (hsl) => {
1250
- let r, g, b;
1251
- let l = hsl.l / 100;
1252
- let s = hsl.s / 100;
1253
- if (hsl.s === 0) {
1254
- r = g = b = l;
1255
- } else {
1256
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1257
- const p = 2 * l - q;
1258
- r = hueToRgb(p, q, hsl.h + 1 / 3);
1259
- g = hueToRgb(p, q, hsl.h);
1260
- b = hueToRgb(p, q, hsl.h - 1 / 3);
1261
- }
1262
- return {
1263
- r: Math.round(r * 255),
1264
- g: Math.round(g * 255),
1265
- b: Math.round(b * 255)
1212
+ const setFilters = (value) => {
1213
+ setTheFilters({
1214
+ ...filters,
1215
+ ...value ?? {}
1216
+ });
1266
1217
  };
1267
- };
1268
- var hslToHex = (hsl) => {
1269
- const l = hsl.l / 100;
1270
- const s = hsl.s;
1271
- const a = s * Math.min(l, 1 - l) / 100;
1272
- const f = (n) => {
1273
- const k = (n + hsl.h / 30) % 12;
1274
- const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
1275
- return Math.round(255 * color).toString(16).padStart(2, "0");
1218
+ const filteredData = useMemo2(() => {
1219
+ let filtered = data;
1220
+ if (!filtered) {
1221
+ return;
1222
+ }
1223
+ if (filters?.amount?.min || filters?.amount?.max) {
1224
+ filtered = applyAmountFilter(filtered, filters.amount);
1225
+ }
1226
+ if (filters?.account) {
1227
+ filtered = applyAccountFilter(filtered, filters.account);
1228
+ }
1229
+ return filtered;
1230
+ }, [filters, data]);
1231
+ const categorize = (id, newCategory, notify) => {
1232
+ const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
1233
+ if (foundBT) {
1234
+ updateOneLocal({ ...foundBT, processing: true, error: void 0 });
1235
+ }
1236
+ return Layer.categorizeBankTransaction(apiUrl, auth.access_token, {
1237
+ params: { businessId, bankTransactionId: id },
1238
+ body: newCategory
1239
+ }).then(({ data: newBT, errors }) => {
1240
+ if (newBT) {
1241
+ newBT.recently_categorized = true;
1242
+ updateOneLocal(newBT);
1243
+ }
1244
+ if (errors) {
1245
+ console.error(errors);
1246
+ throw errors;
1247
+ }
1248
+ if (newBT?.recently_categorized === true && notify) {
1249
+ addToast({ content: "Transaction saved" });
1250
+ }
1251
+ }).catch((err) => {
1252
+ const newBT = data?.find(
1253
+ (x) => x.business_id === businessId && x.id === id
1254
+ );
1255
+ if (newBT) {
1256
+ updateOneLocal({
1257
+ ...newBT,
1258
+ error: err.message,
1259
+ processing: false
1260
+ });
1261
+ }
1262
+ }).finally(() => {
1263
+ touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
1264
+ eventCallbacks?.onTransactionCategorized?.(id);
1265
+ });
1276
1266
  };
1277
- return `#${f(0)}${f(8)}${f(4)}`;
1278
- };
1279
-
1280
- // src/providers/LayerProvider/LayerProvider.tsx
1281
- import { add, isBefore } from "date-fns";
1282
- import useSWR, { SWRConfig } from "swr";
1283
- var reducer = (state, action) => {
1284
- switch (action.type) {
1285
- case "LayerContext.setAuth" /* setAuth */:
1286
- case "LayerContext.setBusiness" /* setBusiness */:
1287
- case "LayerContext.setCategories" /* setCategories */:
1288
- case "LayerContext.setTheme" /* setTheme */:
1289
- case "LayerContext.setOnboardingStep" /* setOnboardingStep */:
1290
- case "LayerContext.setColors" /* setColors */:
1291
- return { ...state, ...action.payload };
1292
- case "LayerContext.setToast" /* setToast */:
1293
- return {
1294
- ...state,
1295
- toasts: [
1296
- ...state.toasts,
1297
- { ...action.payload.toast, isExiting: false }
1298
- ]
1299
- };
1300
- case "LayerContext.setToastExit" /* setToastExit */:
1267
+ const match = (id, matchId, notify) => {
1268
+ const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
1269
+ if (foundBT) {
1270
+ updateOneLocal({ ...foundBT, processing: true, error: void 0 });
1271
+ }
1272
+ return Layer.matchBankTransaction(apiUrl, auth.access_token, {
1273
+ params: { businessId, bankTransactionId: id },
1274
+ body: { match_id: matchId, type: "Confirm_Match" /* CONFIRM_MATCH */ }
1275
+ }).then(({ data: bt, errors }) => {
1276
+ const newBT = data?.find(
1277
+ (x) => x.business_id === businessId && x.id === id
1278
+ );
1279
+ if (newBT) {
1280
+ newBT.recently_categorized = true;
1281
+ newBT.match = bt;
1282
+ newBT.categorization_status = "MATCHED" /* MATCHED */;
1283
+ updateOneLocal(newBT);
1284
+ }
1285
+ if (errors) {
1286
+ console.error(errors);
1287
+ throw errors;
1288
+ }
1289
+ if (newBT?.recently_categorized === true && notify) {
1290
+ addToast({ content: "Transaction saved" });
1291
+ }
1292
+ }).catch((err) => {
1293
+ const newBT = data?.find(
1294
+ (x) => x.business_id === businessId && x.id === id
1295
+ );
1296
+ if (newBT) {
1297
+ updateOneLocal({
1298
+ ...newBT,
1299
+ error: err.message,
1300
+ processing: false
1301
+ });
1302
+ }
1303
+ }).finally(() => {
1304
+ touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
1305
+ eventCallbacks?.onTransactionCategorized?.(id);
1306
+ });
1307
+ };
1308
+ const updateOneLocal = (newBankTransaction) => {
1309
+ const updatedData = rawResponseData?.map((page) => {
1301
1310
  return {
1302
- ...state,
1303
- toasts: state.toasts.map(
1304
- (toast) => toast.id === action.payload.toast.id ? { ...toast, isExiting: false } : toast
1311
+ ...page,
1312
+ data: page.data?.map(
1313
+ (bt) => bt.id === newBankTransaction.id ? newBankTransaction : bt
1305
1314
  )
1306
1315
  };
1307
- case "LayerContext.removeToast" /* removeToast */:
1308
- return {
1309
- ...state,
1310
- toasts: state.toasts.filter((t) => t.id !== action.payload.toast.id)
1311
- };
1312
- default:
1313
- return state;
1314
- }
1316
+ });
1317
+ mutate(updatedData, { revalidate: false });
1318
+ };
1319
+ const shouldHideAfterCategorize = (bankTransaction) => {
1320
+ return filters?.categorizationStatus === "review" /* review */;
1321
+ };
1322
+ const removeAfterCategorize = (bankTransaction) => {
1323
+ if (shouldHideAfterCategorize(bankTransaction)) {
1324
+ const updatedData = rawResponseData?.map((page) => {
1325
+ return {
1326
+ ...page,
1327
+ data: page.data?.filter((bt) => bt.id !== bankTransaction.id)
1328
+ };
1329
+ });
1330
+ mutate(updatedData, { revalidate: false });
1331
+ }
1332
+ };
1333
+ const refetch = () => {
1334
+ mutate();
1335
+ };
1336
+ const fetchMore = () => {
1337
+ if (hasMore) {
1338
+ setSize(size + 1);
1339
+ }
1340
+ };
1341
+ const getCacheKey = (txnFilters) => {
1342
+ return filtersSettingString(txnFilters);
1343
+ };
1344
+ useEffect3(() => {
1345
+ if (isLoading || isValidating) {
1346
+ read("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */, getCacheKey(filters));
1347
+ }
1348
+ }, [isLoading, isValidating]);
1349
+ useEffect3(() => {
1350
+ if (hasBeenTouched(getCacheKey(filters))) {
1351
+ refetch();
1352
+ }
1353
+ }, [syncTimestamps, filters]);
1354
+ const { data: linkedAccounts, refetchAccounts } = useLinkedAccounts();
1355
+ const anyAccountSyncing = useMemo2(
1356
+ () => Boolean(linkedAccounts?.some((item) => item.is_syncing)),
1357
+ [linkedAccounts]
1358
+ );
1359
+ const [pollIntervalMs, setPollIntervalMs] = useState5(INITIAL_POLL_INTERVAL_MS);
1360
+ const transactionsNotSynced = useMemo2(
1361
+ () => loadingStatus === "complete" && anyAccountSyncing && (!data || data?.length === 0),
1362
+ [data, anyAccountSyncing, loadingStatus]
1363
+ );
1364
+ let intervalId = void 0;
1365
+ const [refreshTrigger, setRefreshTrigger] = useState5(-1);
1366
+ useEffect3(() => {
1367
+ if (refreshTrigger !== -1) {
1368
+ refetch();
1369
+ refetchAccounts();
1370
+ }
1371
+ }, [refreshTrigger]);
1372
+ useEffect3(() => {
1373
+ if (anyAccountSyncing) {
1374
+ intervalId = setInterval(() => {
1375
+ setRefreshTrigger(Math.random());
1376
+ }, pollIntervalMs);
1377
+ } else {
1378
+ if (intervalId) {
1379
+ clearInterval(intervalId);
1380
+ }
1381
+ }
1382
+ return () => {
1383
+ if (intervalId) {
1384
+ clearInterval(intervalId);
1385
+ }
1386
+ };
1387
+ }, [anyAccountSyncing, transactionsNotSynced, pollIntervalMs]);
1388
+ useTriggerOnChange(data, anyAccountSyncing, (newTransactionList) => {
1389
+ clearInterval(intervalId);
1390
+ setPollIntervalMs(POLL_INTERVAL_AFTER_TXNS_RECEIVED_MS);
1391
+ touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
1392
+ });
1393
+ return {
1394
+ data: filteredData,
1395
+ metadata: lastMetadata,
1396
+ loadingStatus,
1397
+ isLoading,
1398
+ isValidating,
1399
+ refetch,
1400
+ error: responseError,
1401
+ categorize,
1402
+ match,
1403
+ updateOneLocal,
1404
+ shouldHideAfterCategorize,
1405
+ removeAfterCategorize,
1406
+ filters,
1407
+ setFilters,
1408
+ accountsList,
1409
+ activate,
1410
+ display,
1411
+ fetchMore,
1412
+ hasMore
1413
+ };
1315
1414
  };
1316
- var LayerEnvironment = {
1317
- production: {
1318
- url: "https://auth.layerfi.com/oauth2/token",
1319
- scope: "https://api.layerfi.com/production",
1320
- apiUrl: "https://api.layerfi.com"
1321
- },
1322
- sandbox: {
1323
- url: "https://auth.layerfi.com/oauth2/token",
1324
- scope: "https://sandbox.layerfi.com/sandbox",
1325
- apiUrl: "https://sandbox.layerfi.com"
1326
- },
1327
- staging: {
1328
- url: "https://auth.layerfi.com/oauth2/token",
1329
- scope: "https://sandbox.layerfi.com/sandbox",
1330
- apiUrl: "https://sandbox.layerfi.com"
1415
+
1416
+ // src/providers/BankTransactionsProvider/BankTransactionsProvider.tsx
1417
+ var BankTransactionsProvider = ({
1418
+ children
1419
+ }) => {
1420
+ const bankTransactionsContextData = useBankTransactions();
1421
+ return /* @__PURE__ */ React6.createElement(BankTransactionsContext.Provider, { value: bankTransactionsContextData }, children);
1422
+ };
1423
+
1424
+ // src/config/theme.ts
1425
+ var SHADES = {
1426
+ 50: { s: 1, l: 98 },
1427
+ 100: { s: 1, l: 96 },
1428
+ 200: { s: 1, l: 94 },
1429
+ 300: { s: 2, l: 92 },
1430
+ 500: { s: 5, l: 53 },
1431
+ 600: { s: 7, l: 40 },
1432
+ 700: { s: 9, l: 27 },
1433
+ 800: { s: 12, l: 20 },
1434
+ 1e3: { s: 20, l: 7 }
1435
+ };
1436
+ var COLORS = {
1437
+ dark: {
1438
+ h: 0,
1439
+ s: 0,
1440
+ l: 7
1331
1441
  },
1332
- internalStaging: {
1333
- url: "https://auth.layerfi.com/oauth2/token",
1334
- scope: "https://sandbox.layerfi.com/sandbox",
1335
- apiUrl: "https://staging.layerfi.com"
1442
+ light: {
1443
+ h: 0,
1444
+ s: 0,
1445
+ l: 100
1336
1446
  }
1337
1447
  };
1338
- var LayerProvider = ({
1339
- appId,
1340
- appSecret,
1341
- businessId,
1342
- children,
1343
- businessAccessToken,
1344
- environment = "production",
1345
- theme,
1346
- usePlaidSandbox,
1347
- onError,
1348
- eventCallbacks
1349
- }) => {
1350
- const defaultSWRConfig = {
1351
- revalidateInterval: 0,
1352
- revalidateOnFocus: false,
1353
- revalidateOnReconnect: false,
1354
- revalidateIfStale: false
1355
- };
1356
- errorHandler.setOnError(onError);
1357
- const colors = buildColorsPalette(theme);
1358
- const { url, scope, apiUrl } = LayerEnvironment[environment];
1359
- const [state, dispatch] = useReducer(reducer, {
1360
- auth: {
1361
- access_token: "",
1362
- token_type: "",
1363
- expires_in: 0,
1364
- expires_at: new Date(2e3, 1, 1)
1365
- },
1366
- businessId,
1367
- business: void 0,
1368
- categories: [],
1369
- apiUrl,
1370
- theme,
1371
- colors,
1372
- usePlaidSandbox,
1373
- onboardingStep: void 0,
1374
- environment,
1375
- toasts: [],
1376
- eventCallbacks: {}
1377
- });
1378
- const { touch, syncTimestamps, read, readTimestamps, hasBeenTouched } = useDataSync();
1379
- const { data: auth } = appId !== void 0 && appSecret !== void 0 ? useSWR(
1380
- businessAccessToken === void 0 && appId !== void 0 && appSecret !== void 0 && isBefore(state.auth.expires_at, /* @__PURE__ */ new Date()) && "authenticate",
1381
- Layer.authenticate({
1382
- appId,
1383
- appSecret,
1384
- authenticationUrl: url,
1385
- scope
1386
- }),
1387
- defaultSWRConfig
1388
- ) : { data: void 0 };
1389
- useEffect3(() => {
1390
- if (businessAccessToken) {
1391
- dispatch({
1392
- type: "LayerContext.setAuth" /* setAuth */,
1393
- payload: {
1394
- auth: {
1395
- access_token: businessAccessToken,
1396
- token_type: "Bearer",
1397
- expires_in: 3600,
1398
- expires_at: add(/* @__PURE__ */ new Date(), { seconds: 3600 })
1399
- }
1400
- }
1401
- });
1402
- } else if (auth?.access_token) {
1403
- dispatch({
1404
- type: "LayerContext.setAuth" /* setAuth */,
1405
- payload: {
1406
- auth: {
1407
- ...auth,
1408
- expires_at: add(/* @__PURE__ */ new Date(), { seconds: auth.expires_in })
1409
- }
1410
- }
1411
- });
1448
+
1449
+ // src/utils/colors.ts
1450
+ var parseStylesFromThemeConfig = (theme) => {
1451
+ let styles = {};
1452
+ if (!theme) {
1453
+ return styles;
1454
+ }
1455
+ if (theme.colors) {
1456
+ const darkColor = parseColorFromTheme("dark", theme.colors.dark);
1457
+ const lightColor = parseColorFromTheme("light", theme.colors.light);
1458
+ const textColor = parseTextColorFromTheme(theme.colors.text);
1459
+ styles = { ...styles, ...darkColor, ...lightColor, ...textColor };
1460
+ }
1461
+ return styles;
1462
+ };
1463
+ var parseTextColorFromTheme = (color) => {
1464
+ if (!color) {
1465
+ return {};
1466
+ }
1467
+ try {
1468
+ if ("hex" in color) {
1469
+ return { "--text-color-primary": color.hex };
1412
1470
  }
1413
- }, [businessAccessToken, auth?.access_token]);
1414
- const { data: categoriesData } = useSWR(
1415
- businessId && state.auth?.access_token && `categories-${businessId}`,
1416
- Layer.getCategories(apiUrl, state.auth?.access_token, {
1417
- params: { businessId }
1418
- }),
1419
- {
1420
- ...defaultSWRConfig,
1421
- onSuccess: (response) => {
1422
- if (response?.data?.categories?.length) {
1423
- dispatch({
1424
- type: "LayerContext.setCategories" /* setCategories */,
1425
- payload: { categories: response.data.categories || [] }
1426
- });
1427
- }
1428
- }
1471
+ return {};
1472
+ } catch (_err) {
1473
+ return {};
1474
+ }
1475
+ };
1476
+ var parseColorFromTheme = (colorName, color) => {
1477
+ if (!color) {
1478
+ return {};
1479
+ }
1480
+ try {
1481
+ if ("h" in color && "s" in color && "l" in color) {
1482
+ return {
1483
+ [`--color-${colorName}-h`]: color.h,
1484
+ [`--color-${colorName}-s`]: color.s,
1485
+ [`--color-${colorName}-l`]: color.l
1486
+ };
1429
1487
  }
1430
- );
1431
- useEffect3(() => {
1432
- if (categoriesData?.data?.categories?.length) {
1433
- dispatch({
1434
- type: "LayerContext.setCategories" /* setCategories */,
1435
- payload: { categories: categoriesData.data.categories || [] }
1436
- });
1488
+ if ("r" in color && "g" in color && "b" in color) {
1489
+ const { h, s, l } = rgbToHsl(color);
1490
+ return {
1491
+ [`--color-${colorName}-h`]: h,
1492
+ [`--color-${colorName}-s`]: `${s}%`,
1493
+ [`--color-${colorName}-l`]: `${l}%`
1494
+ };
1437
1495
  }
1438
- }, [categoriesData]);
1439
- const { data: businessData } = useSWR(
1440
- businessId && state?.auth?.access_token && `business-${businessId}`,
1441
- Layer.getBusiness(apiUrl, state?.auth?.access_token, {
1442
- params: { businessId }
1443
- }),
1444
- {
1445
- ...defaultSWRConfig,
1446
- onSuccess: (response) => {
1447
- if (response?.data) {
1448
- dispatch({
1449
- type: "LayerContext.setBusiness" /* setBusiness */,
1450
- payload: { business: response.data || [] }
1451
- });
1452
- }
1496
+ if ("hex" in color) {
1497
+ const rgb = hexToRgb(color.hex);
1498
+ if (!rgb) {
1499
+ return {};
1453
1500
  }
1454
- }
1455
- );
1456
- useEffect3(() => {
1457
- if (businessData?.data) {
1458
- dispatch({
1459
- type: "LayerContext.setBusiness" /* setBusiness */,
1460
- payload: { business: businessData.data || [] }
1501
+ const { h, s, l } = rgbToHsl({
1502
+ r: rgb.r.toString(),
1503
+ g: rgb.g.toString(),
1504
+ b: rgb.b.toString()
1461
1505
  });
1506
+ return {
1507
+ [`--color-${colorName}-h`]: h,
1508
+ [`--color-${colorName}-s`]: `${s}%`,
1509
+ [`--color-${colorName}-l`]: `${l}%`
1510
+ };
1462
1511
  }
1463
- }, [businessData]);
1464
- const setTheme = (theme2) => {
1465
- dispatch({
1466
- type: "LayerContext.setTheme" /* setTheme */,
1467
- payload: { theme: theme2 }
1468
- });
1469
- dispatch({
1470
- type: "LayerContext.setColors" /* setColors */,
1471
- payload: { colors: buildColorsPalette(theme2) }
1472
- });
1473
- };
1474
- const setLightColor = (color) => {
1475
- setTheme({
1476
- ...state.theme ?? {},
1477
- colors: {
1478
- ...state.theme?.colors ?? {},
1479
- light: color
1480
- }
1481
- });
1482
- };
1483
- const setDarkColor = (color) => {
1484
- setTheme({
1485
- ...state.theme ?? {},
1486
- colors: {
1487
- ...state.theme?.colors ?? {},
1488
- dark: color
1489
- }
1490
- });
1491
- };
1492
- const setTextColor = (color) => {
1493
- setTheme({
1494
- ...state.theme ?? {},
1495
- colors: {
1496
- ...state.theme?.colors ?? {},
1497
- text: color
1512
+ return {};
1513
+ } catch (_err) {
1514
+ return {};
1515
+ }
1516
+ };
1517
+ var parseColorFromThemeToHsl = (color) => {
1518
+ if (!color) {
1519
+ return;
1520
+ }
1521
+ try {
1522
+ if ("h" in color && "s" in color && "l" in color) {
1523
+ return {
1524
+ h: Number(color.h),
1525
+ s: Number(color.s),
1526
+ l: Number(color.l)
1527
+ };
1528
+ }
1529
+ if ("r" in color && "g" in color && "b" in color) {
1530
+ const { h, s, l } = rgbToHsl(color);
1531
+ return {
1532
+ h,
1533
+ s,
1534
+ l
1535
+ };
1536
+ }
1537
+ if ("hex" in color) {
1538
+ const rgb = hexToRgb(color.hex);
1539
+ if (!rgb) {
1540
+ return void 0;
1498
1541
  }
1499
- });
1500
- };
1501
- const setToast = (toast) => {
1502
- dispatch({ type: "LayerContext.setToast" /* setToast */, payload: { toast } });
1542
+ const { h, s, l } = rgbToHsl({
1543
+ r: rgb.r.toString(),
1544
+ g: rgb.g.toString(),
1545
+ b: rgb.b.toString()
1546
+ });
1547
+ return {
1548
+ h,
1549
+ s,
1550
+ l
1551
+ };
1552
+ }
1553
+ return;
1554
+ } catch (_err) {
1555
+ return;
1556
+ }
1557
+ };
1558
+ var rgbToHsl = (color) => {
1559
+ let r = Number(color.r);
1560
+ let g = Number(color.g);
1561
+ let b = Number(color.b);
1562
+ r /= 255;
1563
+ g /= 255;
1564
+ b /= 255;
1565
+ const l = Math.max(r, g, b);
1566
+ const s = l - Math.min(r, g, b);
1567
+ const h = s ? l === r ? (g - b) / s : l === g ? 2 + (b - r) / s : 4 + (r - g) / s : 0;
1568
+ return {
1569
+ h: 60 * h < 0 ? 60 * h + 360 : 60 * h,
1570
+ s: 100 * (s ? l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s)) : 0),
1571
+ l: 100 * (2 * l - s) / 2
1503
1572
  };
1504
- const removeToast = (toast) => {
1505
- dispatch({ type: "LayerContext.removeToast" /* removeToast */, payload: { toast } });
1573
+ };
1574
+ var hexToRgb = (hex) => {
1575
+ const values = hex.replace(
1576
+ /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
1577
+ (m, r, g, b) => "#" + r + r + g + g + b + b
1578
+ ).substring(1).match(/.{2}/g)?.map((x) => parseInt(x, 16));
1579
+ if (!values) {
1580
+ return;
1581
+ }
1582
+ return {
1583
+ r: values[0],
1584
+ g: values[1],
1585
+ b: values[2]
1506
1586
  };
1507
- const setToastExit = (toast) => {
1508
- dispatch({ type: "LayerContext.setToastExit" /* setToastExit */, payload: { toast } });
1587
+ };
1588
+ var buildColorsPalette = (theme) => {
1589
+ const darkColor = parseColorFromThemeToHsl(theme?.colors?.dark) ?? COLORS.dark;
1590
+ const lightColor = parseColorFromThemeToHsl(theme?.colors?.light) ?? COLORS.light;
1591
+ return {
1592
+ 50: buildColorShade(50, darkColor),
1593
+ 100: buildColorShade(100, darkColor),
1594
+ 200: buildColorShade(200, darkColor),
1595
+ 300: buildColorShade(300, darkColor),
1596
+ 400: {
1597
+ hsl: lightColor,
1598
+ rgb: hslToRgb(lightColor),
1599
+ hex: hslToHex(lightColor)
1600
+ },
1601
+ 500: buildColorShade(500, darkColor),
1602
+ 600: buildColorShade(600, darkColor),
1603
+ 700: buildColorShade(700, darkColor),
1604
+ 800: buildColorShade(800, darkColor),
1605
+ 900: {
1606
+ hsl: darkColor,
1607
+ rgb: hslToRgb(darkColor),
1608
+ hex: hslToHex(darkColor)
1609
+ },
1610
+ 1e3: buildColorShade(1e3, darkColor)
1509
1611
  };
1510
- const addToast = (toast) => {
1511
- const id = `${Date.now()}-${Math.random()}`;
1512
- const newToast = { id, isExiting: false, ...toast };
1513
- setToast(newToast);
1514
- setTimeout(() => {
1515
- removeToast(newToast);
1516
- setTimeout(() => {
1517
- setToastExit(newToast);
1518
- }, 1e3);
1519
- }, toast.duration || 2e3);
1612
+ };
1613
+ var buildColorShade = (shade, darkColorHsl) => {
1614
+ const hsl = { h: darkColorHsl.h, ...SHADES[shade] };
1615
+ const rgb = hslToRgb(hsl);
1616
+ const hex = hslToHex(hsl);
1617
+ return { hsl, rgb, hex };
1618
+ };
1619
+ var hueToRgb = (p, q, t) => {
1620
+ if (t < 0)
1621
+ t += 1;
1622
+ if (t > 1)
1623
+ t -= 1;
1624
+ if (t < 1 / 6)
1625
+ return p + (q - p) * 6 * t;
1626
+ if (t < 1 / 2)
1627
+ return q;
1628
+ if (t < 2 / 3)
1629
+ return p + (q - p) * (2 / 3 - t) * 6;
1630
+ return p;
1631
+ };
1632
+ var hslToRgb = (hsl) => {
1633
+ let r, g, b;
1634
+ let l = hsl.l / 100;
1635
+ let s = hsl.s / 100;
1636
+ if (hsl.s === 0) {
1637
+ r = g = b = l;
1638
+ } else {
1639
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1640
+ const p = 2 * l - q;
1641
+ r = hueToRgb(p, q, hsl.h + 1 / 3);
1642
+ g = hueToRgb(p, q, hsl.h);
1643
+ b = hueToRgb(p, q, hsl.h - 1 / 3);
1644
+ }
1645
+ return {
1646
+ r: Math.round(r * 255),
1647
+ g: Math.round(g * 255),
1648
+ b: Math.round(b * 255)
1520
1649
  };
1521
- const setColors = (colors2) => setTheme({
1522
- ...state.theme ?? {},
1523
- colors: colors2
1524
- });
1525
- const getColor = (shade) => {
1526
- if (state.colors && shade in state.colors) {
1527
- return state.colors[shade];
1528
- }
1529
- return;
1650
+ };
1651
+ var hslToHex = (hsl) => {
1652
+ const l = hsl.l / 100;
1653
+ const s = hsl.s;
1654
+ const a = s * Math.min(l, 1 - l) / 100;
1655
+ const f = (n) => {
1656
+ const k = (n + hsl.h / 30) % 12;
1657
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
1658
+ return Math.round(255 * color).toString(16).padStart(2, "0");
1530
1659
  };
1531
- const setOnboardingStep = (value) => dispatch({
1532
- type: "LayerContext.setOnboardingStep" /* setOnboardingStep */,
1533
- payload: { onboardingStep: value }
1534
- });
1535
- const drawerContextData = useDrawer();
1536
- return /* @__PURE__ */ React7.createElement(SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ React7.createElement(
1537
- LayerContext.Provider,
1538
- {
1539
- value: {
1540
- ...state,
1541
- setTheme,
1542
- getColor,
1543
- setLightColor,
1544
- setDarkColor,
1545
- setTextColor,
1546
- setColors,
1547
- setOnboardingStep,
1548
- addToast,
1549
- removeToast,
1550
- onError: errorHandler.onError,
1551
- touch,
1552
- read,
1553
- syncTimestamps,
1554
- readTimestamps,
1555
- hasBeenTouched,
1556
- eventCallbacks
1557
- }
1558
- },
1559
- /* @__PURE__ */ React7.createElement(BankTransactionsProvider, null, /* @__PURE__ */ React7.createElement(DrawerContext.Provider, { value: drawerContextData }, children, /* @__PURE__ */ React7.createElement(GlobalWidgets, null)))
1560
- ));
1660
+ return `#${f(0)}${f(8)}${f(4)}`;
1561
1661
  };
1562
1662
 
1563
- // src/components/Onboarding/Onboarding.tsx
1564
- import React44, { useContext as useContext6, useEffect as useEffect6, useState as useState8 } from "react";
1565
-
1566
- // src/contexts/LinkedAccountsContext/LinkedAccountsContext.ts
1567
- import { createContext as createContext4 } from "react";
1568
- var LinkedAccountsContext = createContext4({
1569
- data: void 0,
1570
- isLoading: false,
1571
- loadingStatus: "initial",
1572
- isValidating: false,
1573
- error: void 0,
1574
- updateConnectionStatus: () => {
1575
- },
1576
- addConnection: () => {
1577
- },
1578
- removeConnection: () => {
1579
- },
1580
- repairConnection: () => {
1581
- },
1582
- refetchAccounts: () => {
1583
- },
1584
- unlinkAccount: () => {
1585
- },
1586
- denyAccount: () => {
1587
- },
1588
- confirmAccount: () => {
1589
- },
1590
- breakConnection: () => {
1591
- },
1592
- syncAccounts: () => {
1663
+ // src/providers/LayerProvider/LayerProvider.tsx
1664
+ import { add, isBefore } from "date-fns";
1665
+ import useSWR2, { SWRConfig } from "swr";
1666
+ var reducer = (state, action) => {
1667
+ switch (action.type) {
1668
+ case "LayerContext.setAuth" /* setAuth */:
1669
+ case "LayerContext.setBusiness" /* setBusiness */:
1670
+ case "LayerContext.setCategories" /* setCategories */:
1671
+ case "LayerContext.setTheme" /* setTheme */:
1672
+ case "LayerContext.setOnboardingStep" /* setOnboardingStep */:
1673
+ case "LayerContext.setColors" /* setColors */:
1674
+ return { ...state, ...action.payload };
1675
+ case "LayerContext.setToast" /* setToast */:
1676
+ return {
1677
+ ...state,
1678
+ toasts: [
1679
+ ...state.toasts,
1680
+ { ...action.payload.toast, isExiting: false }
1681
+ ]
1682
+ };
1683
+ case "LayerContext.setToastExit" /* setToastExit */:
1684
+ return {
1685
+ ...state,
1686
+ toasts: state.toasts.map(
1687
+ (toast) => toast.id === action.payload.toast.id ? { ...toast, isExiting: false } : toast
1688
+ )
1689
+ };
1690
+ case "LayerContext.removeToast" /* removeToast */:
1691
+ return {
1692
+ ...state,
1693
+ toasts: state.toasts.filter((t) => t.id !== action.payload.toast.id)
1694
+ };
1695
+ default:
1696
+ return state;
1593
1697
  }
1594
- });
1595
-
1596
- // src/providers/LinkedAccountsProvider/LinkedAccountsProvider.tsx
1597
- import React8 from "react";
1598
-
1599
- // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
1600
- import { useEffect as useEffect4, useState as useState5 } from "react";
1601
- import { usePlaidLink } from "react-plaid-link";
1602
-
1603
- // src/hooks/useLinkedAccounts/mockData.ts
1604
- var LINKED_ACCOUNTS_MOCK_DATA = [
1605
- {
1606
- id: "d800ada8-8075-4436-a712-08efabcbd51a",
1607
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1608
- external_account_source: "PLAID",
1609
- external_account_name: "Citi Double Cash\xAE Card",
1610
- mask: "1234",
1611
- latest_balance_timestamp: {
1612
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1613
- external_account_source: "PLAID",
1614
- balance: 435121,
1615
- at: "2024-04-03T13:00:00Z",
1616
- created_at: "2024-04-06T22:47:59.715458Z"
1617
- },
1618
- current_ledger_balance: 373717,
1619
- institution: {
1620
- name: "Chase",
1621
- logo: ""
1622
- },
1623
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1624
- connection_external_id: "11111",
1625
- connection_needs_repair_as_of: null,
1626
- requires_user_confirmation_as_of: null,
1627
- is_syncing: true
1698
+ };
1699
+ var LayerEnvironment = {
1700
+ production: {
1701
+ url: "https://auth.layerfi.com/oauth2/token",
1702
+ scope: "https://api.layerfi.com/production",
1703
+ apiUrl: "https://api.layerfi.com"
1628
1704
  },
1629
- {
1630
- id: "f98ec50a-c370-484d-a35b-d00207436075",
1631
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1632
- external_account_source: "PLAID",
1633
- external_account_name: "Citi Double Cash\xAE Card",
1634
- mask: "1234",
1635
- latest_balance_timestamp: {
1636
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1637
- external_account_source: "PLAID",
1638
- balance: 435121,
1639
- at: "2024-04-03T13:00:00Z",
1640
- created_at: "2024-04-06T16:44:35.715458Z"
1641
- },
1642
- current_ledger_balance: 373717,
1643
- institution: {
1644
- name: "Chase",
1645
- logo: ""
1646
- },
1647
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1648
- connection_external_id: "11111",
1649
- connection_needs_repair_as_of: null,
1650
- requires_user_confirmation_as_of: null,
1651
- is_syncing: false
1705
+ sandbox: {
1706
+ url: "https://auth.layerfi.com/oauth2/token",
1707
+ scope: "https://sandbox.layerfi.com/sandbox",
1708
+ apiUrl: "https://sandbox.layerfi.com"
1652
1709
  },
1653
- {
1654
- id: "843f1748-fdaa-422d-a73d-2489a40c8dc7",
1655
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1656
- external_account_source: "PLAID",
1657
- external_account_name: "Citi Double Cash\xAE Card",
1658
- mask: "1234",
1659
- latest_balance_timestamp: {
1660
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1661
- external_account_source: "PLAID",
1662
- balance: 435121,
1663
- at: "2024-04-03T13:00:00Z",
1664
- created_at: "2024-04-06T16:44:35.715458Z"
1665
- },
1666
- current_ledger_balance: 373717,
1667
- institution: {
1668
- name: "Chase",
1669
- logo: ""
1670
- },
1671
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1672
- connection_external_id: "11111",
1673
- connection_needs_repair_as_of: "2024-03-06T16:44:35.715458Z",
1674
- requires_user_confirmation_as_of: null,
1675
- is_syncing: false
1710
+ staging: {
1711
+ url: "https://auth.layerfi.com/oauth2/token",
1712
+ scope: "https://sandbox.layerfi.com/sandbox",
1713
+ apiUrl: "https://sandbox.layerfi.com"
1676
1714
  },
1677
- {
1678
- id: "8f430e29-e339-4d71-a08a-fce469c7a7c1",
1679
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1680
- external_account_source: "PLAID",
1681
- external_account_name: "Citi Double Cash\xAE Card",
1682
- mask: "1234",
1683
- latest_balance_timestamp: {
1684
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1685
- external_account_source: "PLAID",
1686
- balance: 435121,
1687
- at: "2024-04-03T13:00:00Z",
1688
- created_at: "2024-04-06T16:44:35.715458Z"
1689
- },
1690
- current_ledger_balance: 373717,
1691
- institution: {
1692
- name: "Chase",
1693
- logo: ""
1694
- },
1695
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1696
- connection_external_id: "11111",
1697
- connection_needs_repair_as_of: null,
1698
- requires_user_confirmation_as_of: "2024-03-06T16:44:35.715458Z",
1699
- is_syncing: false
1715
+ internalStaging: {
1716
+ url: "https://auth.layerfi.com/oauth2/token",
1717
+ scope: "https://sandbox.layerfi.com/sandbox",
1718
+ apiUrl: "https://staging.layerfi.com"
1700
1719
  }
1701
- ];
1702
-
1703
- // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
1704
- import useSWR2 from "swr";
1705
- var DEBUG = true;
1706
- var USE_MOCK_RESPONSE_DATA = false;
1707
- var useLinkedAccounts = () => {
1708
- const {
1709
- auth,
1720
+ };
1721
+ var LayerProvider = ({
1722
+ appId,
1723
+ appSecret,
1724
+ businessId,
1725
+ children,
1726
+ businessAccessToken,
1727
+ environment = "production",
1728
+ theme,
1729
+ usePlaidSandbox,
1730
+ onError,
1731
+ eventCallbacks
1732
+ }) => {
1733
+ const defaultSWRConfig = {
1734
+ revalidateInterval: 0,
1735
+ revalidateOnFocus: false,
1736
+ revalidateOnReconnect: false,
1737
+ revalidateIfStale: false
1738
+ };
1739
+ errorHandler.setOnError(onError);
1740
+ const colors = buildColorsPalette(theme);
1741
+ const { url, scope, apiUrl } = LayerEnvironment[environment];
1742
+ const [state, dispatch] = useReducer(reducer, {
1743
+ auth: {
1744
+ access_token: "",
1745
+ token_type: "",
1746
+ expires_in: 0,
1747
+ expires_at: new Date(2e3, 1, 1)
1748
+ },
1710
1749
  businessId,
1750
+ business: void 0,
1751
+ categories: [],
1711
1752
  apiUrl,
1753
+ theme,
1754
+ colors,
1712
1755
  usePlaidSandbox,
1756
+ onboardingStep: void 0,
1757
+ environment,
1758
+ toasts: [],
1759
+ eventCallbacks: {}
1760
+ });
1761
+ const {
1713
1762
  touch,
1714
- read,
1715
1763
  syncTimestamps,
1716
- hasBeenTouched
1717
- } = useLayerContext();
1718
- const [linkToken, setLinkToken] = useState5(null);
1719
- const [loadingStatus, setLoadingStatus] = useState5("initial");
1720
- const USE_PLAID_SANDBOX = usePlaidSandbox ?? true;
1721
- const [linkMode, setLinkMode] = useState5("add");
1722
- const queryKey = businessId && auth?.access_token && `linked-accounts-${businessId}`;
1723
- const {
1724
- data: responseData,
1725
- isLoading,
1726
- isValidating,
1727
- error: responseError,
1728
- mutate
1729
- } = useSWR2(
1730
- queryKey,
1731
- Layer.getLinkedAccounts(apiUrl, auth?.access_token, {
1732
- params: { businessId }
1733
- })
1734
- );
1735
- useEffect4(() => {
1736
- if (!isLoading && responseData?.data.external_accounts) {
1737
- setLoadingStatus("complete");
1738
- return;
1739
- }
1740
- if (isLoading && loadingStatus === "initial") {
1741
- setLoadingStatus("loading");
1742
- return;
1743
- }
1744
- if (!isLoading && loadingStatus === "loading") {
1745
- setLoadingStatus("complete");
1746
- }
1747
- }, [isLoading]);
1748
- const fetchPlaidLinkToken = async () => {
1749
- if (auth?.access_token) {
1750
- const linkToken2 = (await Layer.getPlaidLinkToken(apiUrl, auth.access_token, {
1751
- params: { businessId }
1752
- })).data.link_token;
1753
- setLinkMode("add");
1754
- setLinkToken(linkToken2);
1755
- }
1756
- };
1757
- const fetchPlaidUpdateModeLinkToken = async (plaidItemPlaidId) => {
1758
- if (auth?.access_token) {
1759
- const linkToken2 = (await Layer.getPlaidUpdateModeLinkToken(apiUrl, auth.access_token, {
1760
- params: { businessId },
1761
- body: { plaid_item_id: plaidItemPlaidId }
1762
- })).data.link_token;
1763
- setLinkMode("update");
1764
- setLinkToken(linkToken2);
1765
- }
1766
- };
1767
- const exchangePlaidPublicToken2 = async (publicToken, metadata) => {
1768
- await Layer.exchangePlaidPublicToken(apiUrl, auth?.access_token, {
1769
- params: { businessId },
1770
- body: { public_token: publicToken, institution: metadata.institution }
1771
- });
1772
- refetchAccounts();
1773
- };
1774
- const { open: plaidLinkStart, ready: plaidLinkReady } = usePlaidLink({
1775
- token: linkToken,
1776
- // If in update mode, we don't need to exchange the public token for an access token.
1777
- // The existing access token will automatically become valid again
1778
- onSuccess: async (publicToken, metadata) => {
1779
- if (linkMode == "add") {
1780
- exchangePlaidPublicToken2(publicToken, metadata);
1781
- } else {
1782
- await updateConnectionStatus2();
1783
- refetchAccounts();
1784
- setLinkMode("add");
1785
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1786
- }
1787
- },
1788
- onExit: () => setLinkMode("add"),
1789
- env: USE_PLAID_SANDBOX ? "sandbox" : void 0
1790
- });
1764
+ read,
1765
+ readTimestamps,
1766
+ hasBeenTouched,
1767
+ resetCaches
1768
+ } = useDataSync();
1769
+ const { data: auth } = appId !== void 0 && appSecret !== void 0 ? useSWR2(
1770
+ businessAccessToken === void 0 && appId !== void 0 && appSecret !== void 0 && isBefore(state.auth.expires_at, /* @__PURE__ */ new Date()) && "authenticate",
1771
+ Layer.authenticate({
1772
+ appId,
1773
+ appSecret,
1774
+ authenticationUrl: url,
1775
+ scope
1776
+ }),
1777
+ defaultSWRConfig
1778
+ ) : { data: void 0 };
1791
1779
  useEffect4(() => {
1792
- if (plaidLinkReady) {
1793
- plaidLinkStart();
1794
- }
1795
- }, [plaidLinkStart, plaidLinkReady]);
1796
- const mockResponseData = {
1797
- data: LINKED_ACCOUNTS_MOCK_DATA,
1798
- meta: {},
1799
- error: void 0
1800
- };
1801
- const addConnection = (source) => {
1802
- if (source === "PLAID") {
1803
- fetchPlaidLinkToken();
1804
- } else {
1805
- console.error(
1806
- `Adding a connection with source ${source} not yet supported`
1807
- );
1808
- }
1809
- };
1810
- const repairConnection = async (source, connectionExternalId) => {
1811
- if (source === "PLAID") {
1812
- await fetchPlaidUpdateModeLinkToken(connectionExternalId);
1813
- } else {
1814
- console.error(
1815
- `Repairing a connection with source ${source} not yet supported`
1816
- );
1817
- }
1818
- };
1819
- const removeConnection = async (source, connectionExternalId) => {
1820
- if (source === "PLAID") {
1821
- await unlinkPlaidItem2(connectionExternalId);
1822
- await refetchAccounts();
1823
- } else {
1824
- console.error(
1825
- `Removing a connection with source ${source} not yet supported`
1826
- );
1827
- }
1828
- };
1829
- const unlinkAccount2 = async (source, accountId) => {
1830
- DEBUG && console.log("unlinking account");
1831
- if (source === "PLAID") {
1832
- await Layer.unlinkAccount(apiUrl, auth?.access_token, {
1833
- params: { businessId, accountId }
1780
+ if (businessAccessToken) {
1781
+ dispatch({
1782
+ type: "LayerContext.setAuth" /* setAuth */,
1783
+ payload: {
1784
+ auth: {
1785
+ access_token: businessAccessToken,
1786
+ token_type: "Bearer",
1787
+ expires_in: 3600,
1788
+ expires_at: add(/* @__PURE__ */ new Date(), { seconds: 3600 })
1789
+ }
1790
+ }
1791
+ });
1792
+ } else if (auth?.access_token) {
1793
+ dispatch({
1794
+ type: "LayerContext.setAuth" /* setAuth */,
1795
+ payload: {
1796
+ auth: {
1797
+ ...auth,
1798
+ expires_at: add(/* @__PURE__ */ new Date(), { seconds: auth.expires_in })
1799
+ }
1800
+ }
1834
1801
  });
1835
- await refetchAccounts();
1836
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1837
- } else {
1838
- console.error(
1839
- `Unlinking an account with source ${source} not yet supported`
1840
- );
1841
1802
  }
1842
- };
1843
- const confirmAccount = async (source, accountId) => {
1844
- DEBUG && console.log("confirming account");
1845
- if (source === "PLAID") {
1846
- await Layer.confirmConnection(apiUrl, auth?.access_token, {
1847
- params: {
1848
- businessId,
1849
- accountId
1803
+ }, [businessAccessToken, auth?.access_token]);
1804
+ const { data: categoriesData } = useSWR2(
1805
+ businessId && state.auth?.access_token && `categories-${businessId}`,
1806
+ Layer.getCategories(apiUrl, state.auth?.access_token, {
1807
+ params: { businessId }
1808
+ }),
1809
+ {
1810
+ ...defaultSWRConfig,
1811
+ onSuccess: (response) => {
1812
+ if (response?.data?.categories?.length) {
1813
+ dispatch({
1814
+ type: "LayerContext.setCategories" /* setCategories */,
1815
+ payload: { categories: response.data.categories || [] }
1816
+ });
1850
1817
  }
1818
+ }
1819
+ }
1820
+ );
1821
+ useEffect4(() => {
1822
+ if (categoriesData?.data?.categories?.length) {
1823
+ dispatch({
1824
+ type: "LayerContext.setCategories" /* setCategories */,
1825
+ payload: { categories: categoriesData.data.categories || [] }
1851
1826
  });
1852
- await refetchAccounts();
1853
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1854
- } else {
1855
- console.error(
1856
- `Confirming an account with source ${source} not yet supported`
1857
- );
1858
1827
  }
1859
- };
1860
- const denyAccount = async (source, accountId) => {
1861
- DEBUG && console.log("confirming account");
1862
- if (source === "PLAID") {
1863
- await Layer.denyConnection(apiUrl, auth?.access_token, {
1864
- params: {
1865
- businessId,
1866
- accountId
1828
+ }, [categoriesData]);
1829
+ const { data: businessData } = useSWR2(
1830
+ businessId && state?.auth?.access_token && `business-${businessId}`,
1831
+ Layer.getBusiness(apiUrl, state?.auth?.access_token, {
1832
+ params: { businessId }
1833
+ }),
1834
+ {
1835
+ ...defaultSWRConfig,
1836
+ onSuccess: (response) => {
1837
+ if (response?.data) {
1838
+ dispatch({
1839
+ type: "LayerContext.setBusiness" /* setBusiness */,
1840
+ payload: { business: response.data || [] }
1841
+ });
1867
1842
  }
1868
- });
1869
- await refetchAccounts();
1870
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1871
- } else {
1872
- console.error(
1873
- `Denying an account with source ${source} not yet supported`
1874
- );
1843
+ }
1875
1844
  }
1876
- };
1877
- const breakConnection = async (source, connectionExternalId) => {
1878
- DEBUG && console.log("Breaking sandbox plaid item connection");
1879
- if (source === "PLAID") {
1880
- await Layer.breakPlaidItemConnection(apiUrl, auth?.access_token, {
1881
- params: {
1882
- businessId,
1883
- plaidItemPlaidId: connectionExternalId
1884
- }
1845
+ );
1846
+ useEffect4(() => {
1847
+ if (businessData?.data) {
1848
+ dispatch({
1849
+ type: "LayerContext.setBusiness" /* setBusiness */,
1850
+ payload: { business: businessData.data || [] }
1885
1851
  });
1886
- await refetchAccounts();
1887
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1888
- } else {
1889
- console.error(
1890
- `Breaking a sandbox connection with source ${source} not yet supported`
1891
- );
1892
1852
  }
1853
+ }, [businessData]);
1854
+ const setTheme = (theme2) => {
1855
+ dispatch({
1856
+ type: "LayerContext.setTheme" /* setTheme */,
1857
+ payload: { theme: theme2 }
1858
+ });
1859
+ dispatch({
1860
+ type: "LayerContext.setColors" /* setColors */,
1861
+ payload: { colors: buildColorsPalette(theme2) }
1862
+ });
1893
1863
  };
1894
- const refetchAccounts = async () => {
1895
- DEBUG && console.log("refetching accounts...");
1896
- await mutate();
1897
- };
1898
- const syncAccounts = async () => {
1899
- DEBUG && console.log("resyncing accounts...");
1900
- await Layer.syncConnection(apiUrl, auth?.access_token, {
1901
- params: { businessId }
1864
+ const setLightColor = (color) => {
1865
+ setTheme({
1866
+ ...state.theme ?? {},
1867
+ colors: {
1868
+ ...state.theme?.colors ?? {},
1869
+ light: color
1870
+ }
1902
1871
  });
1903
1872
  };
1904
- const updateConnectionStatus2 = async () => {
1905
- DEBUG && console.log("updating connection status...");
1906
- await Layer.updateConnectionStatus(apiUrl, auth?.access_token, {
1907
- params: { businessId }
1873
+ const setDarkColor = (color) => {
1874
+ setTheme({
1875
+ ...state.theme ?? {},
1876
+ colors: {
1877
+ ...state.theme?.colors ?? {},
1878
+ dark: color
1879
+ }
1908
1880
  });
1909
1881
  };
1910
- const unlinkPlaidItem2 = async (plaidItemPlaidId) => {
1911
- DEBUG && console.log("unlinking plaid item");
1912
- await Layer.unlinkPlaidItem(apiUrl, auth?.access_token, {
1913
- params: { businessId, plaidItemPlaidId }
1882
+ const setTextColor = (color) => {
1883
+ setTheme({
1884
+ ...state.theme ?? {},
1885
+ colors: {
1886
+ ...state.theme?.colors ?? {},
1887
+ text: color
1888
+ }
1914
1889
  });
1915
- await refetchAccounts();
1916
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1917
1890
  };
1918
- useEffect4(() => {
1919
- if (queryKey && (isLoading || isValidating)) {
1920
- read("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */, queryKey);
1921
- }
1922
- }, [isLoading, isValidating]);
1923
- useEffect4(() => {
1924
- if (queryKey && hasBeenTouched(queryKey)) {
1925
- refetchAccounts();
1891
+ const setToast = (toast) => {
1892
+ dispatch({ type: "LayerContext.setToast" /* setToast */, payload: { toast } });
1893
+ };
1894
+ const removeToast = (toast) => {
1895
+ dispatch({ type: "LayerContext.removeToast" /* removeToast */, payload: { toast } });
1896
+ };
1897
+ const setToastExit = (toast) => {
1898
+ dispatch({ type: "LayerContext.setToastExit" /* setToastExit */, payload: { toast } });
1899
+ };
1900
+ const addToast = (toast) => {
1901
+ const id = `${Date.now()}-${Math.random()}`;
1902
+ const newToast = { id, isExiting: false, ...toast };
1903
+ setToast(newToast);
1904
+ setTimeout(() => {
1905
+ removeToast(newToast);
1906
+ setTimeout(() => {
1907
+ setToastExit(newToast);
1908
+ }, 1e3);
1909
+ }, toast.duration || 2e3);
1910
+ };
1911
+ const setColors = (colors2) => setTheme({
1912
+ ...state.theme ?? {},
1913
+ colors: colors2
1914
+ });
1915
+ const getColor = (shade) => {
1916
+ if (state.colors && shade in state.colors) {
1917
+ return state.colors[shade];
1926
1918
  }
1927
- }, [syncTimestamps]);
1928
- return {
1929
- data: USE_MOCK_RESPONSE_DATA ? mockResponseData.data : responseData?.data.external_accounts,
1930
- isLoading,
1931
- loadingStatus,
1932
- isValidating,
1933
- error: responseError,
1934
- addConnection,
1935
- removeConnection,
1936
- repairConnection,
1937
- refetchAccounts,
1938
- unlinkAccount: unlinkAccount2,
1939
- confirmAccount,
1940
- denyAccount,
1941
- breakConnection,
1942
- syncAccounts,
1943
- updateConnectionStatus: updateConnectionStatus2
1919
+ return;
1944
1920
  };
1921
+ const setOnboardingStep = (value) => dispatch({
1922
+ type: "LayerContext.setOnboardingStep" /* setOnboardingStep */,
1923
+ payload: { onboardingStep: value }
1924
+ });
1925
+ const drawerContextData = useDrawer();
1926
+ return /* @__PURE__ */ React7.createElement(SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ React7.createElement(
1927
+ LayerContext.Provider,
1928
+ {
1929
+ value: {
1930
+ ...state,
1931
+ setTheme,
1932
+ getColor,
1933
+ setLightColor,
1934
+ setDarkColor,
1935
+ setTextColor,
1936
+ setColors,
1937
+ setOnboardingStep,
1938
+ addToast,
1939
+ removeToast,
1940
+ onError: errorHandler.onError,
1941
+ touch,
1942
+ read,
1943
+ syncTimestamps,
1944
+ readTimestamps,
1945
+ expireDataCaches: resetCaches,
1946
+ hasBeenTouched,
1947
+ eventCallbacks
1948
+ }
1949
+ },
1950
+ /* @__PURE__ */ React7.createElement(BankTransactionsProvider, null, /* @__PURE__ */ React7.createElement(DrawerContext.Provider, { value: drawerContextData }, children, /* @__PURE__ */ React7.createElement(GlobalWidgets, null)))
1951
+ ));
1945
1952
  };
1946
1953
 
1954
+ // src/components/Onboarding/Onboarding.tsx
1955
+ import React44, { useContext as useContext6, useEffect as useEffect6, useState as useState8 } from "react";
1956
+
1957
+ // src/contexts/LinkedAccountsContext/LinkedAccountsContext.ts
1958
+ import { createContext as createContext4 } from "react";
1959
+ var LinkedAccountsContext = createContext4({
1960
+ data: void 0,
1961
+ isLoading: false,
1962
+ loadingStatus: "initial",
1963
+ isValidating: false,
1964
+ error: void 0,
1965
+ updateConnectionStatus: () => {
1966
+ },
1967
+ addConnection: () => {
1968
+ },
1969
+ removeConnection: () => {
1970
+ },
1971
+ repairConnection: () => {
1972
+ },
1973
+ refetchAccounts: () => {
1974
+ },
1975
+ unlinkAccount: () => {
1976
+ },
1977
+ denyAccount: () => {
1978
+ },
1979
+ confirmAccount: () => {
1980
+ },
1981
+ breakConnection: () => {
1982
+ },
1983
+ syncAccounts: () => {
1984
+ }
1985
+ });
1986
+
1947
1987
  // src/providers/LinkedAccountsProvider/LinkedAccountsProvider.tsx
1988
+ import React8 from "react";
1948
1989
  var LinkedAccountsProvider = ({
1949
1990
  children
1950
1991
  }) => {
@@ -2218,8 +2259,32 @@ var Sunrise = ({ size = 12, ...props }) => /* @__PURE__ */ React16.createElement
2218
2259
  );
2219
2260
  var Sunrise_default = Sunrise;
2220
2261
 
2262
+ // src/components/BankTransactions/constants.ts
2263
+ var CategorizedCategories = [
2264
+ "CATEGORIZED" /* CATEGORIZED */,
2265
+ "JOURNALING" /* JOURNALING */,
2266
+ "SPLIT" /* SPLIT */,
2267
+ "MATCHED" /* MATCHED */
2268
+ ];
2269
+ var ReviewCategories = [
2270
+ "READY_FOR_INPUT" /* READY_FOR_INPUT */,
2271
+ "LAYER_REVIEW" /* LAYER_REVIEW */
2272
+ ];
2273
+
2274
+ // src/components/BankTransactions/utils.ts
2275
+ var filterVisibility = (scope, bankTransaction) => {
2276
+ const categorized = CategorizedCategories.includes(
2277
+ bankTransaction.categorization_status
2278
+ );
2279
+ const inReview = ReviewCategories.includes(
2280
+ bankTransaction.categorization_status
2281
+ );
2282
+ return scope === "all" /* all */ || scope === "review" /* review */ && inReview || scope === "categorized" /* categorized */ && categorized;
2283
+ };
2284
+ var isCategorized = (bankTransaction) => CategorizedCategories.includes(bankTransaction.categorization_status);
2285
+
2221
2286
  // src/utils/bankTransactions.ts
2222
- import { isWithinInterval, parseISO as parseISO2 } from "date-fns";
2287
+ import { isWithinInterval, parseISO } from "date-fns";
2223
2288
  var hasMatch = (bankTransaction) => {
2224
2289
  return Boolean(
2225
2290
  bankTransaction?.suggested_matches && bankTransaction?.suggested_matches?.length > 0 || bankTransaction?.match
@@ -2247,7 +2312,7 @@ var countTransactionsToReview = ({
2247
2312
  };
2248
2313
  return transactions.filter((tx) => {
2249
2314
  try {
2250
- return filterVisibility("review" /* review */, tx) && isWithinInterval(parseISO2(tx.date), dateRangeInterval);
2315
+ return filterVisibility("review" /* review */, tx) && isWithinInterval(parseISO(tx.date), dateRangeInterval);
2251
2316
  } catch (_err) {
2252
2317
  return false;
2253
2318
  }
@@ -2304,7 +2369,7 @@ var ChevronRight = ({ size = 18, ...props }) => /* @__PURE__ */ React17.createEl
2304
2369
  var ChevronRight_default = ChevronRight;
2305
2370
 
2306
2371
  // src/components/Button/Button.tsx
2307
- import React18, { useRef } from "react";
2372
+ import React18, { useRef as useRef2 } from "react";
2308
2373
  import classNames4 from "classnames";
2309
2374
  var Button = ({
2310
2375
  className,
@@ -2318,7 +2383,7 @@ var Button = ({
2318
2383
  fullWidth,
2319
2384
  ...props
2320
2385
  }) => {
2321
- const buttonRef = useRef(null);
2386
+ const buttonRef = useRef2(null);
2322
2387
  let justifyContent = "center";
2323
2388
  if (justify) {
2324
2389
  justifyContent = justify;
@@ -2989,7 +3054,7 @@ var ExpandButton = ({
2989
3054
 
2990
3055
  // src/components/Button/Link.tsx
2991
3056
  import React35, {
2992
- useRef as useRef4
3057
+ useRef as useRef5
2993
3058
  } from "react";
2994
3059
  import classNames12 from "classnames";
2995
3060
  var Link2 = ({
@@ -3004,7 +3069,7 @@ var Link2 = ({
3004
3069
  fullWidth,
3005
3070
  ...props
3006
3071
  }) => {
3007
- const linkRef = useRef4(null);
3072
+ const linkRef = useRef5(null);
3008
3073
  let justifyContent = "center";
3009
3074
  if (justify) {
3010
3075
  justifyContent = justify;
@@ -3062,7 +3127,7 @@ var Link2 = ({
3062
3127
  };
3063
3128
 
3064
3129
  // src/components/Typography/Text.tsx
3065
- import React36, { useRef as useRef5, useState as useState7, useEffect as useEffect5 } from "react";
3130
+ import React36, { useRef as useRef6, useState as useState7, useEffect as useEffect5 } from "react";
3066
3131
  import classNames13 from "classnames";
3067
3132
  var Text = ({
3068
3133
  as: Component2 = "p",
@@ -3103,7 +3168,7 @@ var TextWithTooltip = ({
3103
3168
  tooltipOptions,
3104
3169
  ...props
3105
3170
  }) => {
3106
- const textElementRef = useRef5();
3171
+ const textElementRef = useRef6();
3107
3172
  const compareSize = () => {
3108
3173
  if (textElementRef.current) {
3109
3174
  const compare = textElementRef.current.children[0].scrollWidth > textElementRef.current.children[0].clientWidth;
@@ -3560,11 +3625,11 @@ var MoreVertical = ({ size = 18, ...props }) => {
3560
3625
  var MoreVertical_default = MoreVertical;
3561
3626
 
3562
3627
  // src/components/HoverMenu/HoverMenu.tsx
3563
- import React49, { useEffect as useEffect7, useRef as useRef6, useState as useState9 } from "react";
3628
+ import React49, { useEffect as useEffect7, useRef as useRef7, useState as useState9 } from "react";
3564
3629
  import classNames17 from "classnames";
3565
3630
  var HoverMenu = ({ children, config }) => {
3566
3631
  const [openMenu, setOpenMenu] = useState9(false);
3567
- const hoverMenuRef = useRef6(null);
3632
+ const hoverMenuRef = useRef7(null);
3568
3633
  const hoverMenuClassName = classNames17(
3569
3634
  "Layer__hover-menu",
3570
3635
  openMenu && "Layer__hover-menu--open"
@@ -4207,9 +4272,9 @@ var LinkedAccountsComponent = ({
4207
4272
  import React109, { useEffect as useEffect19, useMemo as useMemo6, useState as useState25 } from "react";
4208
4273
 
4209
4274
  // src/hooks/useElementSize/useElementSize.ts
4210
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef7 } from "react";
4275
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef8 } from "react";
4211
4276
  var useElementSize = (callback) => {
4212
- const ref = useRef7(null);
4277
+ const ref = useRef8(null);
4213
4278
  useLayoutEffect2(() => {
4214
4279
  const element = ref?.current;
4215
4280
  if (!element) {
@@ -4250,7 +4315,7 @@ var debounce = (fnc, timeout = 300) => {
4250
4315
  import React85 from "react";
4251
4316
 
4252
4317
  // src/components/BankTransactionList/BankTransactionListItem.tsx
4253
- import React84, { useEffect as useEffect12, useRef as useRef11, useState as useState15 } from "react";
4318
+ import React84, { useEffect as useEffect12, useRef as useRef12, useState as useState15 } from "react";
4254
4319
 
4255
4320
  // src/icons/ChevronDownFill.tsx
4256
4321
  import * as React57 from "react";
@@ -4278,7 +4343,7 @@ var ChevronDownFill = ({ size = 18, ...props }) => /* @__PURE__ */ React57.creat
4278
4343
  var ChevronDownFill_default = ChevronDownFill;
4279
4344
 
4280
4345
  // src/components/BankTransactionRow/BankTransactionRow.tsx
4281
- import React82, { useEffect as useEffect11, useRef as useRef10, useState as useState14 } from "react";
4346
+ import React82, { useEffect as useEffect11, useRef as useRef11, useState as useState14 } from "react";
4282
4347
 
4283
4348
  // src/icons/Scissors.tsx
4284
4349
  import * as React58 from "react";
@@ -4696,7 +4761,7 @@ var CategorySelectDrawerContent = ({
4696
4761
 
4697
4762
  // src/components/CategorySelect/CategorySelect.tsx
4698
4763
  import classNames23 from "classnames";
4699
- import { parseISO as parseISO3, format as formatTime } from "date-fns";
4764
+ import { parseISO as parseISO2, format as formatTime } from "date-fns";
4700
4765
  var mapCategoryToOption2 = (category) => {
4701
4766
  return {
4702
4767
  type: "category" /* CATEGORY */,
@@ -4748,7 +4813,7 @@ var Option2 = (props) => {
4748
4813
  ...props,
4749
4814
  className: `${props.className} Layer__select__option-content__match`
4750
4815
  },
4751
- /* @__PURE__ */ React65.createElement("div", { className: "Layer__select__option-content__match__main-row" }, /* @__PURE__ */ React65.createElement("span", { className: "Layer__select__option-content__match__date" }, props.data.payload.date && formatTime(parseISO3(props.data.payload.date), DATE_FORMAT)), /* @__PURE__ */ React65.createElement("span", { className: "Layer__select__option-content__match__description" }, props.data.payload.display_name)),
4816
+ /* @__PURE__ */ React65.createElement("div", { className: "Layer__select__option-content__match__main-row" }, /* @__PURE__ */ React65.createElement("span", { className: "Layer__select__option-content__match__date" }, props.data.payload.date && formatTime(parseISO2(props.data.payload.date), DATE_FORMAT)), /* @__PURE__ */ React65.createElement("span", { className: "Layer__select__option-content__match__description" }, props.data.payload.display_name)),
4752
4817
  /* @__PURE__ */ React65.createElement("div", { className: "Layer__select__option-content__match__amount-row" }, /* @__PURE__ */ React65.createElement("span", { className: "Layer__select__option-content__match__amount" }, "$", centsToDollars(props.data.payload.amount)))
4753
4818
  );
4754
4819
  }
@@ -4878,7 +4943,7 @@ import React80, {
4878
4943
  useState as useState13,
4879
4944
  useCallback,
4880
4945
  useEffect as useEffect10,
4881
- useRef as useRef9
4946
+ useRef as useRef10
4882
4947
  } from "react";
4883
4948
 
4884
4949
  // src/icons/ScissorsFullOpen.tsx
@@ -5040,7 +5105,7 @@ var InputGroup = ({
5040
5105
  };
5041
5106
 
5042
5107
  // src/components/Input/FileInput.tsx
5043
- import React71, { useRef as useRef8 } from "react";
5108
+ import React71, { useRef as useRef9 } from "react";
5044
5109
 
5045
5110
  // src/icons/UploadCloud.tsx
5046
5111
  import * as React70 from "react";
@@ -5095,7 +5160,7 @@ var UploadCloud_default = UploadCloud;
5095
5160
 
5096
5161
  // src/components/Input/FileInput.tsx
5097
5162
  var FileInput = ({ text = "Upload", onUpload }) => {
5098
- const hiddenFileInput = useRef8(null);
5163
+ const hiddenFileInput = useRef9(null);
5099
5164
  const onClick = () => {
5100
5165
  if (hiddenFileInput.current) {
5101
5166
  hiddenFileInput.current.click();
@@ -5196,7 +5261,7 @@ import React75 from "react";
5196
5261
 
5197
5262
  // src/components/BankTransactionRow/MatchBadge.tsx
5198
5263
  import React74 from "react";
5199
- import { parseISO as parseISO4, format as formatTime2 } from "date-fns";
5264
+ import { parseISO as parseISO3, format as formatTime2 } from "date-fns";
5200
5265
  var MatchBadge = ({
5201
5266
  bankTransaction,
5202
5267
  classNamePrefix,
@@ -5209,7 +5274,7 @@ var MatchBadge = ({
5209
5274
  Badge,
5210
5275
  {
5211
5276
  icon: /* @__PURE__ */ React74.createElement(MinimizeTwo_default, { size: 11 }),
5212
- tooltip: /* @__PURE__ */ React74.createElement("span", { className: `${classNamePrefix}__match-tooltip` }, /* @__PURE__ */ React74.createElement("div", { className: `${classNamePrefix}__match-tooltip__date` }, formatTime2(parseISO4(date), dateFormat)), /* @__PURE__ */ React74.createElement("div", { className: `${classNamePrefix}__match-tooltip__description` }, bankTransaction.match?.details?.description ?? ""), /* @__PURE__ */ React74.createElement("div", { className: `${classNamePrefix}__match-tooltip__amount` }, "$", centsToDollars(amount)))
5277
+ tooltip: /* @__PURE__ */ React74.createElement("span", { className: `${classNamePrefix}__match-tooltip` }, /* @__PURE__ */ React74.createElement("div", { className: `${classNamePrefix}__match-tooltip__date` }, formatTime2(parseISO3(date), dateFormat)), /* @__PURE__ */ React74.createElement("div", { className: `${classNamePrefix}__match-tooltip__description` }, bankTransaction.match?.details?.description ?? ""), /* @__PURE__ */ React74.createElement("div", { className: `${classNamePrefix}__match-tooltip__amount` }, "$", centsToDollars(amount)))
5213
5278
  },
5214
5279
  text
5215
5280
  );
@@ -5219,7 +5284,7 @@ var MatchBadge = ({
5219
5284
 
5220
5285
  // src/components/MatchForm/MatchForm.tsx
5221
5286
  import classNames28 from "classnames";
5222
- import { parseISO as parseISO5, format as formatTime3 } from "date-fns";
5287
+ import { parseISO as parseISO4, format as formatTime3 } from "date-fns";
5223
5288
  var MatchForm = ({
5224
5289
  classNamePrefix,
5225
5290
  bankTransaction,
@@ -5258,7 +5323,7 @@ var MatchForm = ({
5258
5323
  {
5259
5324
  className: `Layer__nowrap ${classNamePrefix}__match-table__date`
5260
5325
  },
5261
- /* @__PURE__ */ React75.createElement("span", null, formatTime3(parseISO5(match.details.date), DATE_FORMAT)),
5326
+ /* @__PURE__ */ React75.createElement("span", null, formatTime3(parseISO4(match.details.date), DATE_FORMAT)),
5262
5327
  /* @__PURE__ */ React75.createElement("span", { className: "amount-next-to-date" }, "$", centsToDollars(match.details.amount))
5263
5328
  ),
5264
5329
  /* @__PURE__ */ React75.createElement("div", { className: `${classNamePrefix}__match-table__desc` }, /* @__PURE__ */ React75.createElement(
@@ -5301,7 +5366,7 @@ var MatchForm = ({
5301
5366
  // src/components/MatchForm/MatchFormMobile.tsx
5302
5367
  import React76 from "react";
5303
5368
  import classNames29 from "classnames";
5304
- import { parseISO as parseISO6, format as formatTime4 } from "date-fns";
5369
+ import { parseISO as parseISO5, format as formatTime4 } from "date-fns";
5305
5370
  var MatchFormMobile = ({
5306
5371
  classNamePrefix,
5307
5372
  bankTransaction,
@@ -5348,7 +5413,7 @@ var MatchFormMobile = ({
5348
5413
  size: "sm" /* sm */,
5349
5414
  as: "span"
5350
5415
  },
5351
- formatTime4(parseISO6(match.details.date), MONTH_DAY_FORMAT)
5416
+ formatTime4(parseISO5(match.details.date), MONTH_DAY_FORMAT)
5352
5417
  ))),
5353
5418
  /* @__PURE__ */ React76.createElement("div", { className: `${classNamePrefix}__match-item__col-status` }, selectedMatchId && selectedMatchId === match.id ? /* @__PURE__ */ React76.createElement(
5354
5419
  Check_default,
@@ -5633,7 +5698,7 @@ import classNames32 from "classnames";
5633
5698
  var isAlreadyMatched2 = (bankTransaction) => {
5634
5699
  if (bankTransaction?.match) {
5635
5700
  const foundMatch = bankTransaction.suggested_matches?.find(
5636
- (x) => x.details.id === bankTransaction?.match?.details.id
5701
+ (x) => x.details.id === bankTransaction?.match?.details.id || x.details.id === bankTransaction?.match?.bank_transaction.id
5637
5702
  );
5638
5703
  return foundMatch?.id;
5639
5704
  }
@@ -5671,13 +5736,13 @@ var ExpandedBankTransactionRow = forwardRef5(
5671
5736
  bankTransaction.category ? "categorize" /* categorize */ : hasMatch(bankTransaction) ? "match" /* match */ : "categorize" /* categorize */
5672
5737
  );
5673
5738
  const [selectedMatchId, setSelectedMatchId] = useState13(
5674
- isAlreadyMatched2(bankTransaction)
5739
+ isAlreadyMatched2(bankTransaction) ?? bankTransaction?.suggested_matches?.[0]?.id
5675
5740
  );
5676
5741
  const [matchFormError, setMatchFormError] = useState13();
5677
5742
  const [splitFormError, setSplitFormError] = useState13();
5678
5743
  const [height, setHeight] = useState13(0);
5679
5744
  const [isOver, setOver] = useState13(false);
5680
- const bodyRef = useRef9(null);
5745
+ const bodyRef = useRef10(null);
5681
5746
  const [memoText, setMemoText] = useState13();
5682
5747
  const [receiptUrls, setReceiptUrls] = useState13([]);
5683
5748
  const [isLoaded, setIsLoaded] = useState13(false);
@@ -5776,7 +5841,6 @@ var ExpandedBankTransactionRow = forwardRef5(
5776
5841
  setSplitFormError(void 0);
5777
5842
  };
5778
5843
  const save = async () => {
5779
- const endpoint = `/v1/businesses/${businessId}/bank-transactions/${bankTransaction.id}/metadata`;
5780
5844
  if (showDescriptions && memoText != void 0) {
5781
5845
  const result = await Layer.updateBankTransactionMetadata(
5782
5846
  apiUrl,
@@ -5795,9 +5859,12 @@ var ExpandedBankTransactionRow = forwardRef5(
5795
5859
  if (purpose === "match" /* match */) {
5796
5860
  if (!selectedMatchId) {
5797
5861
  setMatchFormError("Select an option to match the transaction");
5862
+ return;
5798
5863
  } else if (selectedMatchId && selectedMatchId !== isAlreadyMatched2(bankTransaction)) {
5799
- onMatchSubmit(selectedMatchId);
5864
+ await onMatchSubmit(selectedMatchId);
5865
+ return;
5800
5866
  }
5867
+ close();
5801
5868
  return;
5802
5869
  }
5803
5870
  if (!validateSplit(rowState)) {
@@ -6148,7 +6215,7 @@ var SplitTooltipDetails = ({
6148
6215
 
6149
6216
  // src/components/BankTransactionRow/BankTransactionRow.tsx
6150
6217
  import classNames33 from "classnames";
6151
- import { parseISO as parseISO7, format as formatTime5 } from "date-fns";
6218
+ import { parseISO as parseISO6, format as formatTime5 } from "date-fns";
6152
6219
  var extractDescriptionForSplit = (category) => {
6153
6220
  if (!category.entries) {
6154
6221
  return "";
@@ -6180,12 +6247,12 @@ var BankTransactionRow = ({
6180
6247
  showReceiptUploads,
6181
6248
  stringOverrides
6182
6249
  }) => {
6183
- const expandedRowRef = useRef10(null);
6250
+ const expandedRowRef = useRef11(null);
6184
6251
  const [showRetry, setShowRetry] = useState14(false);
6185
6252
  const {
6186
- filters,
6187
6253
  categorize: categorizeBankTransaction2,
6188
- match: matchBankTransaction2
6254
+ match: matchBankTransaction2,
6255
+ shouldHideAfterCategorize
6189
6256
  } = useBankTransactionsContext();
6190
6257
  const [selectedCategory, setSelectedCategory] = useState14(
6191
6258
  getDefaultSelectedCategory(bankTransaction)
@@ -6223,7 +6290,7 @@ var BankTransactionRow = ({
6223
6290
  }
6224
6291
  }, [bankTransaction.error]);
6225
6292
  useEffect11(() => {
6226
- if (editable && bankTransaction.recently_categorized) {
6293
+ if (editable && bankTransaction.recently_categorized && shouldHideAfterCategorize(bankTransaction)) {
6227
6294
  setTimeout(() => {
6228
6295
  removeTransaction(bankTransaction);
6229
6296
  }, 300);
@@ -6256,7 +6323,7 @@ var BankTransactionRow = ({
6256
6323
  const openClassName = open ? `${className}--expanded` : "";
6257
6324
  const rowClassName = classNames33(
6258
6325
  className,
6259
- bankTransaction.recently_categorized && editable ? "Layer__bank-transaction-row--removing" : "",
6326
+ bankTransaction.recently_categorized && editable && shouldHideAfterCategorize(bankTransaction) ? "Layer__bank-transaction-row--removing" : "",
6260
6327
  open ? openClassName : "",
6261
6328
  initialLoad ? "initial-load" : "",
6262
6329
  showComponent ? "show" : ""
@@ -6267,7 +6334,7 @@ var BankTransactionRow = ({
6267
6334
  className: "Layer__table-cell Layer__bank-transaction-table__date-col",
6268
6335
  ...openRow
6269
6336
  },
6270
- /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, formatTime5(parseISO7(bankTransaction.date), dateFormat))
6337
+ /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, formatTime5(parseISO6(bankTransaction.date), dateFormat))
6271
6338
  ), /* @__PURE__ */ React82.createElement(
6272
6339
  "td",
6273
6340
  {
@@ -6357,7 +6424,7 @@ var BankTransactionRow = ({
6357
6424
  dateFormat
6358
6425
  }
6359
6426
  ), /* @__PURE__ */ React82.createElement("span", { className: `${className}__category-text__text` }, `${formatTime5(
6360
- parseISO7(bankTransaction.match.bank_transaction.date),
6427
+ parseISO6(bankTransaction.match.bank_transaction.date),
6361
6428
  dateFormat
6362
6429
  )}, ${bankTransaction.match?.details?.description}`)), bankTransaction?.categorization_status !== "MATCHED" /* MATCHED */ && bankTransaction?.categorization_status !== "SPLIT" /* SPLIT */ && /* @__PURE__ */ React82.createElement("span", { className: `${className}__category-text__text` }, bankTransaction?.category?.display_name)) : null,
6363
6430
  !categorized && !open && showRetry ? /* @__PURE__ */ React82.createElement(
@@ -6432,7 +6499,7 @@ var BankTransactionRow = ({
6432
6499
 
6433
6500
  // src/components/BankTransactionList/Assignment.tsx
6434
6501
  import React83 from "react";
6435
- import { parseISO as parseISO8, format as formatTime6 } from "date-fns";
6502
+ import { parseISO as parseISO7, format as formatTime6 } from "date-fns";
6436
6503
  var Assignment = ({ bankTransaction }) => {
6437
6504
  if (bankTransaction.match && bankTransaction.categorization_status === "MATCHED" /* MATCHED */) {
6438
6505
  return /* @__PURE__ */ React83.createElement(React83.Fragment, null, /* @__PURE__ */ React83.createElement(
@@ -6444,7 +6511,7 @@ var Assignment = ({ bankTransaction }) => {
6444
6511
  text: "Matched"
6445
6512
  }
6446
6513
  ), /* @__PURE__ */ React83.createElement(Text, { className: "Layer__bank-transaction-list-item__category-text__text" }, `${formatTime6(
6447
- parseISO8(bankTransaction.match.bank_transaction.date),
6514
+ parseISO7(bankTransaction.match.bank_transaction.date),
6448
6515
  DATE_FORMAT
6449
6516
  )}, ${bankTransaction.match.bank_transaction.description ?? bankTransaction.match?.details?.description}`));
6450
6517
  }
@@ -6469,7 +6536,7 @@ var Assignment = ({ bankTransaction }) => {
6469
6536
 
6470
6537
  // src/components/BankTransactionList/BankTransactionListItem.tsx
6471
6538
  import classNames34 from "classnames";
6472
- import { parseISO as parseISO9, format as formatTime7 } from "date-fns";
6539
+ import { parseISO as parseISO8, format as formatTime7 } from "date-fns";
6473
6540
  var BankTransactionListItem = ({
6474
6541
  index = 0,
6475
6542
  dateFormat,
@@ -6482,9 +6549,13 @@ var BankTransactionListItem = ({
6482
6549
  removeTransaction,
6483
6550
  stringOverrides
6484
6551
  }) => {
6485
- const expandedRowRef = useRef11(null);
6552
+ const expandedRowRef = useRef12(null);
6486
6553
  const [showRetry, setShowRetry] = useState15(false);
6487
- const { categorize: categorizeBankTransaction2, match: matchBankTransaction2 } = useBankTransactionsContext();
6554
+ const {
6555
+ categorize: categorizeBankTransaction2,
6556
+ match: matchBankTransaction2,
6557
+ shouldHideAfterCategorize
6558
+ } = useBankTransactionsContext();
6488
6559
  const [selectedCategory, setSelectedCategory] = useState15(
6489
6560
  getDefaultSelectedCategory(bankTransaction)
6490
6561
  );
@@ -6506,7 +6577,7 @@ var BankTransactionListItem = ({
6506
6577
  }
6507
6578
  }, [bankTransaction.error]);
6508
6579
  useEffect12(() => {
6509
- if (editable && bankTransaction.recently_categorized) {
6580
+ if (editable && bankTransaction.recently_categorized && shouldHideAfterCategorize(bankTransaction)) {
6510
6581
  setTimeout(() => {
6511
6582
  removeTransaction(bankTransaction);
6512
6583
  }, 300);
@@ -6534,11 +6605,11 @@ var BankTransactionListItem = ({
6534
6605
  const openClassName = open ? `${className}--expanded` : "";
6535
6606
  const rowClassName = classNames34(
6536
6607
  className,
6537
- bankTransaction.recently_categorized && editable ? "Layer__bank-transaction-row--removing" : "",
6608
+ bankTransaction.recently_categorized && editable && shouldHideAfterCategorize(bankTransaction) ? "Layer__bank-transaction-row--removing" : "",
6538
6609
  open ? openClassName : "",
6539
6610
  showComponent ? "show" : ""
6540
6611
  );
6541
- return /* @__PURE__ */ React84.createElement("li", { className: rowClassName }, /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading` }, /* @__PURE__ */ React84.createElement("div", { className: `${className}__heading__main` }, /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading-date` }, formatTime7(parseISO9(bankTransaction.date), dateFormat)), /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading-separator` }), /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading-account-name` }, bankTransaction.account_name ?? "")), /* @__PURE__ */ React84.createElement(
6612
+ return /* @__PURE__ */ React84.createElement("li", { className: rowClassName }, /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading` }, /* @__PURE__ */ React84.createElement("div", { className: `${className}__heading__main` }, /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading-date` }, formatTime7(parseISO8(bankTransaction.date), dateFormat)), /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading-separator` }), /* @__PURE__ */ React84.createElement("span", { className: `${className}__heading-account-name` }, bankTransaction.account_name ?? "")), /* @__PURE__ */ React84.createElement(
6542
6613
  "div",
6543
6614
  {
6544
6615
  onClick: toggleOpen,
@@ -6648,7 +6719,7 @@ var BankTransactionList = ({
6648
6719
  import React93 from "react";
6649
6720
 
6650
6721
  // src/components/BankTransactionMobileList/BankTransactionMobileListItem.tsx
6651
- import React92, { useContext as useContext11, useEffect as useEffect17, useRef as useRef12, useState as useState22 } from "react";
6722
+ import React92, { useContext as useContext11, useEffect as useEffect17, useRef as useRef13, useState as useState22 } from "react";
6652
6723
 
6653
6724
  // src/components/BankTransactionMobileList/BankTransactionMobileForms.tsx
6654
6725
  import React91 from "react";
@@ -7105,7 +7176,7 @@ var TransactionToOpenContext = createContext5({
7105
7176
 
7106
7177
  // src/components/BankTransactionMobileList/BankTransactionMobileListItem.tsx
7107
7178
  import classNames36 from "classnames";
7108
- import { parseISO as parseISO10, format as formatTime8 } from "date-fns";
7179
+ import { parseISO as parseISO9, format as formatTime8 } from "date-fns";
7109
7180
  var DATE_FORMAT2 = "LLL d";
7110
7181
  var getAssignedValue2 = (bankTransaction) => {
7111
7182
  if (bankTransaction.categorization_status === "SPLIT" /* SPLIT */) {
@@ -7130,13 +7201,14 @@ var BankTransactionMobileListItem = ({
7130
7201
  setTransactionIdToOpen,
7131
7202
  clearTransactionIdToOpen
7132
7203
  } = useContext11(TransactionToOpenContext);
7204
+ const { shouldHideAfterCategorize } = useBankTransactionsContext();
7133
7205
  const formRowRef = useElementSize(
7134
7206
  (_a, _b, { height: height2 }) => setHeight(height2)
7135
7207
  );
7136
7208
  const headingRowRef = useElementSize((_a, _b, { height: height2 }) => {
7137
7209
  setHeadingHeight(height2);
7138
7210
  });
7139
- const itemRef = useRef12(null);
7211
+ const itemRef = useRef13(null);
7140
7212
  const [removeAnim, setRemoveAnim] = useState22(false);
7141
7213
  const [purpose, setPurpose] = useState22(
7142
7214
  bankTransaction.category ? bankTransaction.categorization_status === "SPLIT" /* SPLIT */ ? "more" /* more */ : "business" /* business */ : hasMatch(bankTransaction) ? "more" /* more */ : "business" /* business */
@@ -7163,7 +7235,7 @@ var BankTransactionMobileListItem = ({
7163
7235
  }, [transactionIdToOpen]);
7164
7236
  useEffect17(() => {
7165
7237
  if (!removeAnim && bankTransaction.recently_categorized) {
7166
- if (editable) {
7238
+ if (editable && shouldHideAfterCategorize(bankTransaction)) {
7167
7239
  setRemoveAnim(true);
7168
7240
  openNext();
7169
7241
  } else {
@@ -7196,7 +7268,7 @@ var BankTransactionMobileListItem = ({
7196
7268
  }
7197
7269
  }, []);
7198
7270
  useEffect17(() => {
7199
- if (editable && bankTransaction.recently_categorized) {
7271
+ if (editable && bankTransaction.recently_categorized && shouldHideAfterCategorize(bankTransaction)) {
7200
7272
  setTimeout(() => {
7201
7273
  removeTransaction(bankTransaction);
7202
7274
  }, 300);
@@ -7227,7 +7299,7 @@ var BankTransactionMobileListItem = ({
7227
7299
  },
7228
7300
  isCredit(bankTransaction) ? "+$" : " $",
7229
7301
  centsToDollars(bankTransaction.amount)
7230
- ), /* @__PURE__ */ React92.createElement("span", { className: `${className}__heading__date` }, formatTime8(parseISO10(bankTransaction.date), DATE_FORMAT2))))
7302
+ ), /* @__PURE__ */ React92.createElement("span", { className: `${className}__heading__date` }, formatTime8(parseISO9(bankTransaction.date), DATE_FORMAT2))))
7231
7303
  ), categorizationEnabled(mode) ? /* @__PURE__ */ React92.createElement(
7232
7304
  "div",
7233
7305
  {
@@ -7750,11 +7822,11 @@ var DownloadCloud = ({ size = 18, ...props }) => /* @__PURE__ */ React103.create
7750
7822
  var DownloadCloud_default = DownloadCloud;
7751
7823
 
7752
7824
  // src/utils/business.ts
7753
- import { differenceInCalendarMonths, parseISO as parseISO11, startOfMonth } from "date-fns";
7825
+ import { differenceInCalendarMonths, parseISO as parseISO10, startOfMonth } from "date-fns";
7754
7826
  var getActivationDate = (business) => {
7755
7827
  try {
7756
7828
  if (business && business.activation_at) {
7757
- return parseISO11(business.activation_at);
7829
+ return parseISO10(business.activation_at);
7758
7830
  }
7759
7831
  return;
7760
7832
  } catch (_err) {
@@ -7780,7 +7852,7 @@ var isDateAllowedToBrowse = (date, business) => {
7780
7852
  };
7781
7853
 
7782
7854
  // src/components/DatePicker/DatePicker.tsx
7783
- import React105, { useEffect as useEffect18, useRef as useRef13, useState as useState23 } from "react";
7855
+ import React105, { useEffect as useEffect18, useRef as useRef14, useState as useState23 } from "react";
7784
7856
  import ReactDatePicker from "react-datepicker";
7785
7857
 
7786
7858
  // src/components/DatePicker/DatePickerOptions.tsx
@@ -7943,7 +8015,7 @@ var DatePicker = ({
7943
8015
  navigateArrows = mode === "monthPicker",
7944
8016
  ...props
7945
8017
  }) => {
7946
- const pickerRef = useRef13(null);
8018
+ const pickerRef = useRef14(null);
7947
8019
  const [updatePickerDate, setPickerDate] = useState23(false);
7948
8020
  const [selectedDates, setSelectedDates] = useState23(selected);
7949
8021
  const { isDesktop } = useSizeClass();
@@ -8339,7 +8411,7 @@ var DataStates = ({
8339
8411
  editable
8340
8412
  }) => {
8341
8413
  let title = editable ? "You are up to date with transactions!" : "You have no categorized transactions";
8342
- let description = editable ? "All uncategorized transaction will be displayed here" : "All transaction will be displayed here once reviewed";
8414
+ let description = editable ? "All uncategorized transactions will be displayed here" : "All transactions will be displayed here once reviewed";
8343
8415
  const showRefreshButton = bankTransactions?.length;
8344
8416
  return /* @__PURE__ */ React108.createElement(React108.Fragment, null, !isLoading && !error && (bankTransactions === void 0 || bankTransactions !== void 0 && bankTransactions.length === 0) ? /* @__PURE__ */ React108.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React108.createElement(
8345
8417
  DataState,
@@ -8364,10 +8436,9 @@ var DataStates = ({
8364
8436
  };
8365
8437
 
8366
8438
  // src/components/BankTransactions/BankTransactions.tsx
8367
- import { endOfMonth as endOfMonth3, parseISO as parseISO12, startOfMonth as startOfMonth4 } from "date-fns";
8439
+ import { endOfMonth as endOfMonth3, parseISO as parseISO11, startOfMonth as startOfMonth4 } from "date-fns";
8368
8440
  var COMPONENT_NAME2 = "bank-transactions";
8369
8441
  var TEST_EMPTY_STATE = false;
8370
- var POLL_INTERVAL = 1e3;
8371
8442
  var categorizationEnabled = (mode) => {
8372
8443
  if (mode === "bookkeeping-client") {
8373
8444
  return false;
@@ -8415,39 +8486,11 @@ var BankTransactionsContent = ({
8415
8486
  fetchMore,
8416
8487
  removeAfterCategorize
8417
8488
  } = useBankTransactionsContext();
8418
- const { data: linkedAccounts, refetchAccounts } = useLinkedAccounts();
8489
+ const { data: linkedAccounts } = useLinkedAccounts();
8419
8490
  const isSyncing = useMemo6(
8420
8491
  () => Boolean(linkedAccounts?.some((item) => item.is_syncing)),
8421
8492
  [linkedAccounts]
8422
8493
  );
8423
- const transactionsNotSynced = useMemo6(
8424
- () => loadingStatus === "complete" && isSyncing && (!data || data?.length === 0),
8425
- [data, isSyncing, loadingStatus]
8426
- );
8427
- let intervalId = void 0;
8428
- const [refreshTrigger, setRefreshTrigger] = useState25(-1);
8429
- useEffect19(() => {
8430
- if (refreshTrigger !== -1) {
8431
- refetch();
8432
- refetchAccounts();
8433
- }
8434
- }, [refreshTrigger]);
8435
- useEffect19(() => {
8436
- if (isSyncing) {
8437
- intervalId = setInterval(() => {
8438
- setRefreshTrigger(Math.random());
8439
- }, POLL_INTERVAL);
8440
- } else {
8441
- if (intervalId) {
8442
- clearInterval(intervalId);
8443
- }
8444
- }
8445
- return () => {
8446
- if (intervalId) {
8447
- clearInterval(intervalId);
8448
- }
8449
- };
8450
- }, [isSyncing, transactionsNotSynced]);
8451
8494
  useEffect19(() => {
8452
8495
  activate();
8453
8496
  }, []);
@@ -8489,7 +8532,7 @@ var BankTransactionsContent = ({
8489
8532
  const bankTransactions = TEST_EMPTY_STATE ? [] : useMemo6(() => {
8490
8533
  if (monthlyView) {
8491
8534
  return data?.filter(
8492
- (x) => parseISO12(x.date) >= dateRange.startDate && parseISO12(x.date) <= dateRange.endDate
8535
+ (x) => parseISO11(x.date) >= dateRange.startDate && parseISO11(x.date) <= dateRange.endDate
8493
8536
  );
8494
8537
  }
8495
8538
  const firstPageIndex = (currentPage - 1) * pageSize;
@@ -8625,7 +8668,7 @@ var BankTransactionsContent = ({
8625
8668
  import React110 from "react";
8626
8669
 
8627
8670
  // src/hooks/useQuickbooks/useQuickbooks.ts
8628
- import { useEffect as useEffect20, useRef as useRef14, useState as useState26 } from "react";
8671
+ import { useEffect as useEffect20, useRef as useRef16, useState as useState26 } from "react";
8629
8672
  var DEBUG2 = true;
8630
8673
  var useQuickbooks = () => {
8631
8674
  const { auth, businessId, apiUrl } = useLayerContext();
@@ -8633,7 +8676,7 @@ var useQuickbooks = () => {
8633
8676
  const [quickbooksIsLinked, setQuickbooksIsLinked] = useState26(
8634
8677
  null
8635
8678
  );
8636
- const syncStatusIntervalRef = useRef14(null);
8679
+ const syncStatusIntervalRef = useRef16(null);
8637
8680
  useEffect20(() => {
8638
8681
  if (isSyncingFromQuickbooks && syncStatusIntervalRef.current === null) {
8639
8682
  const interval = setInterval(() => fetchIsSyncingFromQuickbooks(), 2e3);
@@ -11084,7 +11127,7 @@ var TableRow = ({
11084
11127
  };
11085
11128
 
11086
11129
  // src/components/Table/Table.tsx
11087
- import React128, { useEffect as useEffect26, useRef as useRef15 } from "react";
11130
+ import React128, { useEffect as useEffect26, useRef as useRef17 } from "react";
11088
11131
  import classNames47 from "classnames";
11089
11132
  var Table = ({
11090
11133
  componentName,
@@ -11092,8 +11135,8 @@ var Table = ({
11092
11135
  borderCollapse = "separate",
11093
11136
  bottomSpacing = true
11094
11137
  }) => {
11095
- const tableRef = useRef15(null);
11096
- const prevChildrenRef = useRef15([]);
11138
+ const tableRef = useRef17(null);
11139
+ const prevChildrenRef = useRef17([]);
11097
11140
  useEffect26(() => {
11098
11141
  if (tableRef.current) {
11099
11142
  const tbody = tableRef.current.querySelector("tbody");
@@ -12304,7 +12347,10 @@ var useChartOfAccounts = ({ withDates, startDate: initialStartDate, endDate: ini
12304
12347
  }
12305
12348
  const data2 = {
12306
12349
  name: form.data.name ?? "",
12307
- stable_name: form.data.stable_name,
12350
+ stable_name: form.data.stable_name ? {
12351
+ type: "StableName",
12352
+ stable_name: form.data.stable_name
12353
+ } : void 0,
12308
12354
  parent_id: form.data.parent ? {
12309
12355
  type: "AccountId",
12310
12356
  id: form.data.parent.value
@@ -13081,7 +13127,7 @@ var Card = ({ children, className }) => {
13081
13127
 
13082
13128
  // src/components/DateTime/DateTime.tsx
13083
13129
  import React149 from "react";
13084
- import { parseISO as parseISO13, format as formatTime9 } from "date-fns";
13130
+ import { parseISO as parseISO12, format as formatTime9 } from "date-fns";
13085
13131
  var DateTime = ({
13086
13132
  value,
13087
13133
  format: format7,
@@ -13091,10 +13137,10 @@ var DateTime = ({
13091
13137
  onlyTime
13092
13138
  }) => {
13093
13139
  if (format7) {
13094
- return /* @__PURE__ */ React149.createElement(Text, { className: "Layer__datetime" }, formatTime9(parseISO13(value), format7));
13140
+ return /* @__PURE__ */ React149.createElement(Text, { className: "Layer__datetime" }, formatTime9(parseISO12(value), format7));
13095
13141
  }
13096
- const date = formatTime9(parseISO13(value), dateFormat ?? DATE_FORMAT);
13097
- const time = formatTime9(parseISO13(value), timeFormat ?? TIME_FORMAT);
13142
+ const date = formatTime9(parseISO12(value), dateFormat ?? DATE_FORMAT);
13143
+ const time = formatTime9(parseISO12(value), timeFormat ?? TIME_FORMAT);
13098
13144
  return /* @__PURE__ */ React149.createElement(Text, { className: "Layer__datetime" }, !onlyTime && /* @__PURE__ */ React149.createElement(
13099
13145
  Text,
13100
13146
  {
@@ -13259,7 +13305,7 @@ var LedgerAccountEntryDetails = ({ stringOverrides }) => {
13259
13305
  // src/components/LedgerAccount/LedgerAccountRow.tsx
13260
13306
  import React153, { useContext as useContext23, useEffect as useEffect36, useState as useState40 } from "react";
13261
13307
  import classNames54 from "classnames";
13262
- import { parseISO as parseISO14, format as formatTime10 } from "date-fns";
13308
+ import { parseISO as parseISO13, format as formatTime10 } from "date-fns";
13263
13309
  var LedgerAccountRow = ({
13264
13310
  row,
13265
13311
  index,
@@ -13298,7 +13344,7 @@ var LedgerAccountRow = ({
13298
13344
  }
13299
13345
  }
13300
13346
  },
13301
- /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell Layer__ledger-account-table__tablet-main-col" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ React153.createElement("div", { className: "Layer__ledger-account-table__tablet-main-col__date" }, /* @__PURE__ */ React153.createElement(Text, null, row.date && formatTime10(parseISO14(row.date), DATE_FORMAT)), /* @__PURE__ */ React153.createElement(
13347
+ /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell Layer__ledger-account-table__tablet-main-col" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ React153.createElement("div", { className: "Layer__ledger-account-table__tablet-main-col__date" }, /* @__PURE__ */ React153.createElement(Text, null, row.date && formatTime10(parseISO13(row.date), DATE_FORMAT)), /* @__PURE__ */ React153.createElement(
13302
13348
  Text,
13303
13349
  {
13304
13350
  weight: "normal" /* normal */,
@@ -13331,7 +13377,7 @@ var LedgerAccountRow = ({
13331
13377
  }
13332
13378
  }
13333
13379
  },
13334
- /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell Layer__ledger-account-table__tablet-main-col" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ React153.createElement("div", { className: "Layer__ledger-account-table__tablet-main-col__date" }, /* @__PURE__ */ React153.createElement(Text, null, row.date && formatTime10(parseISO14(row.date), DATE_FORMAT)), /* @__PURE__ */ React153.createElement(
13380
+ /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell Layer__ledger-account-table__tablet-main-col" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ React153.createElement("div", { className: "Layer__ledger-account-table__tablet-main-col__date" }, /* @__PURE__ */ React153.createElement(Text, null, row.date && formatTime10(parseISO13(row.date), DATE_FORMAT)), /* @__PURE__ */ React153.createElement(
13335
13381
  Text,
13336
13382
  {
13337
13383
  weight: "normal" /* normal */,
@@ -13360,7 +13406,7 @@ var LedgerAccountRow = ({
13360
13406
  }
13361
13407
  }
13362
13408
  },
13363
- /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, row.date && formatTime10(parseISO14(row.date), DATE_FORMAT))),
13409
+ /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, row.date && formatTime10(parseISO13(row.date), DATE_FORMAT))),
13364
13410
  /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, row.entry_id.substring(0, 5))),
13365
13411
  /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, row.source?.display_description ?? "")),
13366
13412
  /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, row.direction === "DEBIT" /* DEBIT */ && `$${centsToDollars(row?.amount || 0)}`)),
@@ -13870,7 +13916,7 @@ import React161, { useContext as useContext31, useMemo as useMemo17, useState as
13870
13916
  // src/components/JournalRow/JournalRow.tsx
13871
13917
  import React156, { useContext as useContext26, useEffect as useEffect39, useState as useState44 } from "react";
13872
13918
  import classNames56 from "classnames";
13873
- import { parseISO as parseISO15, format as formatTime11 } from "date-fns";
13919
+ import { parseISO as parseISO14, format as formatTime11 } from "date-fns";
13874
13920
  var INDENTATION2 = 24;
13875
13921
  var EXPANDED_STYLE3 = {
13876
13922
  height: "100%",
@@ -13983,7 +14029,7 @@ var JournalRow = ({
13983
14029
  )
13984
14030
  ))),
13985
14031
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, row.id.substring(0, 5))),
13986
- /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, row.date && formatTime11(parseISO15(row.date), DATE_FORMAT))),
14032
+ /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, row.date && formatTime11(parseISO14(row.date), DATE_FORMAT))),
13987
14033
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, humanizeEnum(row.entry_type))),
13988
14034
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, `(${row.line_items.length})`)),
13989
14035
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, "$", centsToDollars(
@@ -15461,7 +15507,7 @@ var GeneralLedgerView = ({
15461
15507
  };
15462
15508
 
15463
15509
  // src/views/Reports/Reports.tsx
15464
- import React180, { useContext as useContext38, useRef as useRef16, useState as useState55 } from "react";
15510
+ import React180, { useContext as useContext38, useRef as useRef18, useState as useState55 } from "react";
15465
15511
  var DownloadButton2 = ({
15466
15512
  stringOverrides
15467
15513
  }) => {
@@ -15533,7 +15579,7 @@ var Reports = ({
15533
15579
  stringOverrides,
15534
15580
  enabledReports = ["profitAndLoss", "balanceSheet", "statementOfCashFlow"]
15535
15581
  }) => {
15536
- const containerRef = useRef16(null);
15582
+ const containerRef = useRef18(null);
15537
15583
  const [activeTab, setActiveTab] = useState55(enabledReports[0]);
15538
15584
  const options = getOptions(enabledReports);
15539
15585
  const defaultTitle = enabledReports.length > 1 ? "Reports" : options.find((option) => option.value = enabledReports[0])?.label;
@@ -15601,10 +15647,10 @@ var ReportsPanel = ({
15601
15647
  };
15602
15648
 
15603
15649
  // src/components/ProfitAndLossView/ProfitAndLossView.tsx
15604
- import React181, { useContext as useContext39, useRef as useRef17 } from "react";
15650
+ import React181, { useContext as useContext39, useRef as useRef19 } from "react";
15605
15651
  var COMPONENT_NAME7 = "profit-and-loss";
15606
15652
  var ProfitAndLossView = (props) => {
15607
- const containerRef = useRef17(null);
15653
+ const containerRef = useRef19(null);
15608
15654
  return /* @__PURE__ */ React181.createElement(Container, { name: COMPONENT_NAME7, ref: containerRef }, /* @__PURE__ */ React181.createElement(ProfitAndLoss, null, /* @__PURE__ */ React181.createElement(ProfitAndLossPanel, { containerRef, ...props })));
15609
15655
  };
15610
15656
  var ProfitAndLossPanel = ({
@@ -15699,6 +15745,7 @@ export {
15699
15745
  StatementOfCashFlow,
15700
15746
  Tasks,
15701
15747
  useBankTransactionsContext,
15748
+ useDataSync,
15702
15749
  useLayerContext
15703
15750
  };
15704
15751
  //# sourceMappingURL=index.js.map