@layerfi/components 0.1.51 → 0.1.53

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,12 +657,13 @@ 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) => {
666
+ DisplayState2["all"] = "all";
637
667
  DisplayState2["review"] = "review";
638
668
  DisplayState2["categorized"] = "categorized";
639
669
  return DisplayState2;
@@ -662,6 +692,7 @@ var BankTransactionsContext = createContext3({
662
692
  pagination: void 0
663
693
  },
664
694
  updateOneLocal: () => void 0,
695
+ shouldHideAfterCategorize: () => false,
665
696
  removeAfterCategorize: () => void 0,
666
697
  activate: () => void 0,
667
698
  display: "review" /* review */,
@@ -672,7 +703,7 @@ var BankTransactionsContext = createContext3({
672
703
  var useBankTransactionsContext = () => useContext4(BankTransactionsContext);
673
704
 
674
705
  // src/hooks/useBankTransactions/useBankTransactions.tsx
675
- import { useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
706
+ import { useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState5 } from "react";
676
707
 
677
708
  // src/components/BankTransactions/constants.ts
678
709
  var CategorizedCategories = [
@@ -686,1262 +717,1287 @@ var ReviewCategories = [
686
717
  "LAYER_REVIEW" /* LAYER_REVIEW */
687
718
  ];
688
719
 
689
- // src/components/BankTransactions/utils.ts
690
- var filterVisibility = (scope, bankTransaction) => {
691
- const categorized = CategorizedCategories.includes(
692
- bankTransaction.categorization_status
693
- );
694
- const inReview = ReviewCategories.includes(
695
- bankTransaction.categorization_status
696
- );
697
- return scope === "review" /* review */ && inReview || scope === "categorized" /* categorized */ && categorized;
698
- };
699
- var isCategorized = (bankTransaction) => CategorizedCategories.includes(bankTransaction.categorization_status);
720
+ // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
721
+ import { useEffect as useEffect2, useState as useState4 } from "react";
722
+ import { usePlaidLink } from "react-plaid-link";
700
723
 
701
- // src/hooks/useBankTransactions/utils.ts
702
- import { parseISO } from "date-fns";
703
- var collectAccounts = (transactions) => {
704
- const accounts = [];
705
- if (!transactions) {
706
- return accounts;
707
- }
708
- transactions.forEach((x) => {
709
- if (!accounts.find((y) => y.id === x.source_account_id)) {
710
- accounts.push({
711
- id: x.source_account_id,
712
- name: x.account_name || ""
713
- });
714
- }
715
- });
716
- return accounts.sort((a, b) => a.name.localeCompare(b.name));
717
- };
718
- var applyAmountFilter = (data, filter) => {
719
- return data?.filter((x) => {
720
- if ((filter?.min || filter?.min === 0) && (filter?.max || filter?.max === 0)) {
721
- return x.amount >= filter.min * 100 && x.amount <= filter.max * 100;
722
- }
723
- if (filter?.min || filter?.min === 0) {
724
- return x.amount >= filter.min * 100;
725
- }
726
- if (filter?.max || filter?.max === 0) {
727
- return x.amount <= filter.max * 100;
728
- }
729
- });
730
- };
731
- var applyAccountFilter = (data, filter) => data?.filter((x) => filter && filter.includes(x.source_account_id));
732
- var applyDirectionFilter = (data, filter) => {
733
- if (!filter) {
734
- return data;
735
- }
736
- const normalizedFilter = filter.map((x) => x.toLowerCase());
737
- return data?.filter(
738
- (x) => normalizedFilter.includes(x.direction?.toLowerCase())
739
- );
740
- };
741
- var applyCategorizationStatusFilter = (data, filter) => {
742
- if (!filter) {
743
- return data;
724
+ // src/hooks/useLinkedAccounts/mockData.ts
725
+ var LINKED_ACCOUNTS_MOCK_DATA = [
726
+ {
727
+ id: "d800ada8-8075-4436-a712-08efabcbd51a",
728
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
729
+ external_account_source: "PLAID",
730
+ external_account_name: "Citi Double Cash\xAE Card",
731
+ mask: "1234",
732
+ latest_balance_timestamp: {
733
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
734
+ external_account_source: "PLAID",
735
+ balance: 435121,
736
+ at: "2024-04-03T13:00:00Z",
737
+ created_at: "2024-04-06T22:47:59.715458Z"
738
+ },
739
+ current_ledger_balance: 373717,
740
+ institution: {
741
+ name: "Chase",
742
+ logo: ""
743
+ },
744
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
745
+ connection_external_id: "11111",
746
+ connection_needs_repair_as_of: null,
747
+ requires_user_confirmation_as_of: null,
748
+ is_syncing: true
749
+ },
750
+ {
751
+ id: "f98ec50a-c370-484d-a35b-d00207436075",
752
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
753
+ external_account_source: "PLAID",
754
+ external_account_name: "Citi Double Cash\xAE Card",
755
+ mask: "1234",
756
+ latest_balance_timestamp: {
757
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
758
+ external_account_source: "PLAID",
759
+ balance: 435121,
760
+ at: "2024-04-03T13:00:00Z",
761
+ created_at: "2024-04-06T16:44:35.715458Z"
762
+ },
763
+ current_ledger_balance: 373717,
764
+ institution: {
765
+ name: "Chase",
766
+ logo: ""
767
+ },
768
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
769
+ connection_external_id: "11111",
770
+ connection_needs_repair_as_of: null,
771
+ requires_user_confirmation_as_of: null,
772
+ is_syncing: false
773
+ },
774
+ {
775
+ id: "843f1748-fdaa-422d-a73d-2489a40c8dc7",
776
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
777
+ external_account_source: "PLAID",
778
+ external_account_name: "Citi Double Cash\xAE Card",
779
+ mask: "1234",
780
+ latest_balance_timestamp: {
781
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
782
+ external_account_source: "PLAID",
783
+ balance: 435121,
784
+ at: "2024-04-03T13:00:00Z",
785
+ created_at: "2024-04-06T16:44:35.715458Z"
786
+ },
787
+ current_ledger_balance: 373717,
788
+ institution: {
789
+ name: "Chase",
790
+ logo: ""
791
+ },
792
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
793
+ connection_external_id: "11111",
794
+ connection_needs_repair_as_of: "2024-03-06T16:44:35.715458Z",
795
+ requires_user_confirmation_as_of: null,
796
+ is_syncing: false
797
+ },
798
+ {
799
+ id: "8f430e29-e339-4d71-a08a-fce469c7a7c1",
800
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
801
+ external_account_source: "PLAID",
802
+ external_account_name: "Citi Double Cash\xAE Card",
803
+ mask: "1234",
804
+ latest_balance_timestamp: {
805
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
806
+ external_account_source: "PLAID",
807
+ balance: 435121,
808
+ at: "2024-04-03T13:00:00Z",
809
+ created_at: "2024-04-06T16:44:35.715458Z"
810
+ },
811
+ current_ledger_balance: 373717,
812
+ institution: {
813
+ name: "Chase",
814
+ logo: ""
815
+ },
816
+ connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
817
+ connection_external_id: "11111",
818
+ connection_needs_repair_as_of: null,
819
+ requires_user_confirmation_as_of: "2024-03-06T16:44:35.715458Z",
820
+ is_syncing: false
744
821
  }
745
- return data?.filter(
746
- (tx) => filterVisibility(filter, tx) || filter === "review" /* review */ && tx.recently_categorized || filter === "categorized" /* categorized */ && tx.recently_categorized
747
- );
748
- };
749
- var appplyDateRangeFilter = (data, filter) => {
750
- return data?.filter((x) => {
751
- const txDate = parseISO(x.date);
752
- if (filter?.startDate && filter?.endDate) {
753
- return txDate >= filter.startDate && txDate <= filter.endDate;
754
- }
755
- if (filter?.startDate) {
756
- return txDate >= filter.startDate;
757
- }
758
- if (filter?.endDate) {
759
- return txDate <= filter.endDate;
760
- }
761
- });
762
- };
822
+ ];
763
823
 
764
- // src/hooks/useBankTransactions/useBankTransactions.tsx
765
- import useSWRInfinite from "swr/infinite";
766
- var useBankTransactions = (params) => {
824
+ // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
825
+ import useSWR from "swr";
826
+ var DEBUG = true;
827
+ var USE_MOCK_RESPONSE_DATA = false;
828
+ var useLinkedAccounts = () => {
767
829
  const {
768
830
  auth,
769
831
  businessId,
770
832
  apiUrl,
771
- addToast,
833
+ usePlaidSandbox,
772
834
  touch,
773
835
  read,
774
836
  syncTimestamps,
775
- hasBeenTouched,
776
- eventCallbacks
837
+ hasBeenTouched
777
838
  } = useLayerContext();
778
- const { scope = void 0 } = params ?? {};
779
- const [filters, setTheFilters] = useState4(
780
- scope ? { categorizationStatus: scope } : void 0
781
- );
782
- const display = useMemo2(() => {
783
- if (filters?.categorizationStatus === "review" /* review */) {
784
- return "review" /* review */;
785
- }
786
- return "categorized" /* categorized */;
787
- }, [filters?.categorizationStatus]);
788
- const [active, setActive] = useState4(false);
839
+ const [linkToken, setLinkToken] = useState4(null);
789
840
  const [loadingStatus, setLoadingStatus] = useState4("initial");
790
- const getKey = (_index, prevData) => {
791
- if (!auth?.access_token || !active) {
792
- return [false, void 0];
793
- }
794
- if (!prevData?.meta?.pagination?.cursor) {
795
- return [
796
- businessId && auth?.access_token && `bank-transactions-${businessId}`,
797
- void 0
798
- ];
799
- }
800
- return [
801
- businessId && auth?.access_token && `bank-transactions-${businessId}-${prevData.meta.pagination.cursor}`,
802
- prevData.meta.pagination.cursor
803
- ];
804
- };
841
+ const USE_PLAID_SANDBOX = usePlaidSandbox ?? true;
842
+ const [linkMode, setLinkMode] = useState4("add");
843
+ const queryKey = businessId && auth?.access_token && `linked-accounts-${businessId}`;
805
844
  const {
806
- data: rawResponseData,
845
+ data: responseData,
807
846
  isLoading,
808
847
  isValidating,
809
848
  error: responseError,
810
- mutate,
811
- size,
812
- setSize
813
- } = useSWRInfinite(
814
- getKey,
815
- async ([query, nextCursor]) => {
816
- if (auth?.access_token) {
817
- return Layer.getBankTransactions(apiUrl, auth?.access_token, {
818
- params: {
819
- businessId,
820
- cursor: nextCursor
821
- }
822
- }).call(false);
823
- }
824
- return {};
825
- },
826
- {
827
- initialSize: 1,
828
- revalidateFirstPage: false
829
- }
830
- );
831
- const data = useMemo2(() => {
832
- if (rawResponseData && rawResponseData.length > 0) {
833
- return rawResponseData?.map((x) => x?.data).flat().filter((x) => !!x);
834
- }
835
- return void 0;
836
- }, [rawResponseData]);
837
- const lastMetadata = useMemo2(() => {
838
- if (rawResponseData && rawResponseData.length > 0) {
839
- return rawResponseData[rawResponseData.length - 1].meta;
840
- }
841
- return void 0;
842
- }, [rawResponseData]);
843
- const hasMore = useMemo2(() => {
844
- if (rawResponseData && rawResponseData.length > 0) {
845
- const lastElement = rawResponseData[rawResponseData.length - 1];
846
- return Boolean(
847
- lastElement.meta?.pagination?.cursor && lastElement.meta?.pagination?.has_more
848
- );
849
- }
850
- return false;
851
- }, [rawResponseData]);
852
- const accountsList = useMemo2(
853
- () => data ? collectAccounts(data) : [],
854
- [data]
849
+ mutate
850
+ } = useSWR(
851
+ queryKey,
852
+ Layer.getLinkedAccounts(apiUrl, auth?.access_token, {
853
+ params: { businessId }
854
+ })
855
855
  );
856
856
  useEffect2(() => {
857
+ if (!isLoading && responseData?.data.external_accounts) {
858
+ setLoadingStatus("complete");
859
+ return;
860
+ }
857
861
  if (isLoading && loadingStatus === "initial") {
858
862
  setLoadingStatus("loading");
859
863
  return;
860
864
  }
861
865
  if (!isLoading && loadingStatus === "loading") {
862
866
  setLoadingStatus("complete");
863
- return;
864
867
  }
865
868
  }, [isLoading]);
866
- const activate = () => {
867
- setActive(true);
869
+ const fetchPlaidLinkToken = async () => {
870
+ if (auth?.access_token) {
871
+ const linkToken2 = (await Layer.getPlaidLinkToken(apiUrl, auth.access_token, {
872
+ params: { businessId }
873
+ })).data.link_token;
874
+ setLinkMode("add");
875
+ setLinkToken(linkToken2);
876
+ }
868
877
  };
869
- const setFilters = (value) => {
870
- setTheFilters({
871
- ...filters,
872
- ...value ?? {}
878
+ const fetchPlaidUpdateModeLinkToken = async (plaidItemPlaidId) => {
879
+ if (auth?.access_token) {
880
+ const linkToken2 = (await Layer.getPlaidUpdateModeLinkToken(apiUrl, auth.access_token, {
881
+ params: { businessId },
882
+ body: { plaid_item_id: plaidItemPlaidId }
883
+ })).data.link_token;
884
+ setLinkMode("update");
885
+ setLinkToken(linkToken2);
886
+ }
887
+ };
888
+ const exchangePlaidPublicToken2 = async (publicToken, metadata) => {
889
+ await Layer.exchangePlaidPublicToken(apiUrl, auth?.access_token, {
890
+ params: { businessId },
891
+ body: { public_token: publicToken, institution: metadata.institution }
873
892
  });
893
+ refetchAccounts();
874
894
  };
875
- const filteredData = useMemo2(() => {
876
- let filtered = data;
877
- if (!filtered) {
878
- return;
879
- }
880
- if (filters?.amount?.min || filters?.amount?.max) {
881
- filtered = applyAmountFilter(filtered, filters.amount);
882
- }
883
- if (filters?.account) {
884
- filtered = applyAccountFilter(filtered, filters.account);
885
- }
886
- if (filters?.direction) {
887
- filtered = applyDirectionFilter(filtered, filters.direction);
895
+ const { open: plaidLinkStart, ready: plaidLinkReady } = usePlaidLink({
896
+ token: linkToken,
897
+ // If in update mode, we don't need to exchange the public token for an access token.
898
+ // The existing access token will automatically become valid again
899
+ onSuccess: async (publicToken, metadata) => {
900
+ if (linkMode == "add") {
901
+ exchangePlaidPublicToken2(publicToken, metadata);
902
+ } else {
903
+ await updateConnectionStatus2();
904
+ refetchAccounts();
905
+ setLinkMode("add");
906
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
907
+ }
908
+ },
909
+ onExit: () => setLinkMode("add"),
910
+ env: USE_PLAID_SANDBOX ? "sandbox" : void 0
911
+ });
912
+ useEffect2(() => {
913
+ if (plaidLinkReady) {
914
+ plaidLinkStart();
888
915
  }
889
- if (filters?.categorizationStatus) {
890
- filtered = applyCategorizationStatusFilter(
891
- filtered,
892
- filters.categorizationStatus
916
+ }, [plaidLinkStart, plaidLinkReady]);
917
+ const mockResponseData = {
918
+ data: LINKED_ACCOUNTS_MOCK_DATA,
919
+ meta: {},
920
+ error: void 0
921
+ };
922
+ const addConnection = (source) => {
923
+ if (source === "PLAID") {
924
+ fetchPlaidLinkToken();
925
+ } else {
926
+ console.error(
927
+ `Adding a connection with source ${source} not yet supported`
893
928
  );
894
929
  }
895
- if (filters?.dateRange?.startDate || filters?.dateRange?.endDate) {
896
- filtered = appplyDateRangeFilter(filtered, filters?.dateRange);
930
+ };
931
+ const repairConnection = async (source, connectionExternalId) => {
932
+ if (source === "PLAID") {
933
+ await fetchPlaidUpdateModeLinkToken(connectionExternalId);
934
+ } else {
935
+ console.error(
936
+ `Repairing a connection with source ${source} not yet supported`
937
+ );
897
938
  }
898
- return filtered;
899
- }, [filters, data]);
900
- const categorize = (id, newCategory, notify) => {
901
- const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
902
- if (foundBT) {
903
- updateOneLocal({ ...foundBT, processing: true, error: void 0 });
939
+ };
940
+ const removeConnection = async (source, connectionExternalId) => {
941
+ if (source === "PLAID") {
942
+ await unlinkPlaidItem2(connectionExternalId);
943
+ await refetchAccounts();
944
+ } else {
945
+ console.error(
946
+ `Removing a connection with source ${source} not yet supported`
947
+ );
904
948
  }
905
- return Layer.categorizeBankTransaction(apiUrl, auth.access_token, {
906
- params: { businessId, bankTransactionId: id },
907
- body: newCategory
908
- }).then(({ data: newBT, errors }) => {
909
- if (newBT) {
910
- newBT.recently_categorized = true;
911
- updateOneLocal(newBT);
912
- }
913
- if (errors) {
914
- console.error(errors);
915
- throw errors;
916
- }
917
- if (newBT?.recently_categorized === true && notify) {
918
- addToast({ content: "Transaction saved" });
919
- }
920
- }).catch((err) => {
921
- const newBT = data?.find(
922
- (x) => x.business_id === businessId && x.id === id
949
+ };
950
+ const unlinkAccount2 = async (source, accountId) => {
951
+ DEBUG && console.log("unlinking account");
952
+ if (source === "PLAID") {
953
+ await Layer.unlinkAccount(apiUrl, auth?.access_token, {
954
+ params: { businessId, accountId }
955
+ });
956
+ await refetchAccounts();
957
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
958
+ } else {
959
+ console.error(
960
+ `Unlinking an account with source ${source} not yet supported`
923
961
  );
924
- if (newBT) {
925
- updateOneLocal({
926
- ...newBT,
927
- error: err.message,
928
- processing: false
929
- });
930
- }
931
- }).finally(() => {
932
- touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
933
- eventCallbacks?.onTransactionCategorized?.(id);
934
- });
962
+ }
935
963
  };
936
- const match = (id, matchId, notify) => {
937
- const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
938
- if (foundBT) {
939
- updateOneLocal({ ...foundBT, processing: true, error: void 0 });
964
+ const confirmAccount = async (source, accountId) => {
965
+ DEBUG && console.log("confirming account");
966
+ if (source === "PLAID") {
967
+ await Layer.confirmConnection(apiUrl, auth?.access_token, {
968
+ params: {
969
+ businessId,
970
+ accountId
971
+ }
972
+ });
973
+ await refetchAccounts();
974
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
975
+ } else {
976
+ console.error(
977
+ `Confirming an account with source ${source} not yet supported`
978
+ );
940
979
  }
941
- return Layer.matchBankTransaction(apiUrl, auth.access_token, {
942
- params: { businessId, bankTransactionId: id },
943
- body: { match_id: matchId, type: "Confirm_Match" /* CONFIRM_MATCH */ }
944
- }).then(({ data: bt, errors }) => {
945
- const newBT = data?.find(
946
- (x) => x.business_id === businessId && x.id === id
980
+ };
981
+ const denyAccount = async (source, accountId) => {
982
+ DEBUG && console.log("confirming account");
983
+ if (source === "PLAID") {
984
+ await Layer.denyConnection(apiUrl, auth?.access_token, {
985
+ params: {
986
+ businessId,
987
+ accountId
988
+ }
989
+ });
990
+ await refetchAccounts();
991
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
992
+ } else {
993
+ console.error(
994
+ `Denying an account with source ${source} not yet supported`
947
995
  );
948
- if (newBT) {
949
- newBT.recently_categorized = true;
950
- newBT.match = bt;
951
- newBT.categorization_status = "MATCHED" /* MATCHED */;
952
- updateOneLocal(newBT);
953
- }
954
- if (errors) {
955
- console.error(errors);
956
- throw errors;
957
- }
958
- if (newBT?.recently_categorized === true && notify) {
959
- addToast({ content: "Transaction saved" });
960
- }
961
- }).catch((err) => {
962
- const newBT = data?.find(
963
- (x) => x.business_id === businessId && x.id === id
996
+ }
997
+ };
998
+ const breakConnection = async (source, connectionExternalId) => {
999
+ DEBUG && console.log("Breaking sandbox plaid item connection");
1000
+ if (source === "PLAID") {
1001
+ await Layer.breakPlaidItemConnection(apiUrl, auth?.access_token, {
1002
+ params: {
1003
+ businessId,
1004
+ plaidItemPlaidId: connectionExternalId
1005
+ }
1006
+ });
1007
+ await refetchAccounts();
1008
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1009
+ } else {
1010
+ console.error(
1011
+ `Breaking a sandbox connection with source ${source} not yet supported`
964
1012
  );
965
- if (newBT) {
966
- updateOneLocal({
967
- ...newBT,
968
- error: err.message,
969
- processing: false
970
- });
971
- }
972
- }).finally(() => {
973
- touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
974
- eventCallbacks?.onTransactionCategorized?.(id);
975
- });
1013
+ }
976
1014
  };
977
- const updateOneLocal = (newBankTransaction) => {
978
- const updatedData = rawResponseData?.map((page) => {
979
- return {
980
- ...page,
981
- data: page.data?.map(
982
- (bt) => bt.id === newBankTransaction.id ? newBankTransaction : bt
983
- )
984
- };
985
- });
986
- mutate(updatedData, { revalidate: false });
1015
+ const refetchAccounts = async () => {
1016
+ DEBUG && console.log("refetching accounts...");
1017
+ await mutate();
987
1018
  };
988
- const removeAfterCategorize = (bankTransaction) => {
1019
+ const syncAccounts = async () => {
1020
+ DEBUG && console.log("resyncing accounts...");
1021
+ await Layer.syncConnection(apiUrl, auth?.access_token, {
1022
+ params: { businessId }
1023
+ });
989
1024
  };
990
- const refetch = () => {
991
- mutate();
1025
+ const updateConnectionStatus2 = async () => {
1026
+ DEBUG && console.log("updating connection status...");
1027
+ await Layer.updateConnectionStatus(apiUrl, auth?.access_token, {
1028
+ params: { businessId }
1029
+ });
992
1030
  };
993
- const fetchMore = () => {
994
- if (hasMore) {
995
- setSize(size + 1);
996
- }
1031
+ const unlinkPlaidItem2 = async (plaidItemPlaidId) => {
1032
+ DEBUG && console.log("unlinking plaid item");
1033
+ await Layer.unlinkPlaidItem(apiUrl, auth?.access_token, {
1034
+ params: { businessId, plaidItemPlaidId }
1035
+ });
1036
+ await refetchAccounts();
1037
+ touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
997
1038
  };
998
1039
  useEffect2(() => {
999
- if (isLoading || isValidating) {
1000
- read("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */, "bank-transactions");
1040
+ if (queryKey && (isLoading || isValidating)) {
1041
+ read("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */, queryKey);
1001
1042
  }
1002
1043
  }, [isLoading, isValidating]);
1003
1044
  useEffect2(() => {
1004
- if (hasBeenTouched("bank-transactions")) {
1005
- refetch();
1045
+ if (queryKey && hasBeenTouched(queryKey)) {
1046
+ refetchAccounts();
1006
1047
  }
1007
1048
  }, [syncTimestamps]);
1008
1049
  return {
1009
- data: filteredData,
1010
- metadata: lastMetadata,
1011
- loadingStatus,
1050
+ data: USE_MOCK_RESPONSE_DATA ? mockResponseData.data : responseData?.data.external_accounts,
1012
1051
  isLoading,
1052
+ loadingStatus,
1013
1053
  isValidating,
1014
- refetch,
1015
1054
  error: responseError,
1016
- categorize,
1017
- match,
1018
- updateOneLocal,
1019
- removeAfterCategorize,
1020
- filters,
1021
- setFilters,
1022
- accountsList,
1023
- activate,
1024
- display,
1025
- fetchMore,
1026
- hasMore
1055
+ addConnection,
1056
+ removeConnection,
1057
+ repairConnection,
1058
+ refetchAccounts,
1059
+ unlinkAccount: unlinkAccount2,
1060
+ confirmAccount,
1061
+ denyAccount,
1062
+ breakConnection,
1063
+ syncAccounts,
1064
+ updateConnectionStatus: updateConnectionStatus2
1027
1065
  };
1028
1066
  };
1029
1067
 
1030
- // src/providers/BankTransactionsProvider/BankTransactionsProvider.tsx
1031
- var BankTransactionsProvider = ({
1032
- children
1033
- }) => {
1034
- const bankTransactionsContextData = useBankTransactions();
1035
- return /* @__PURE__ */ React6.createElement(BankTransactionsContext.Provider, { value: bankTransactionsContextData }, children);
1036
- };
1037
-
1038
- // src/config/theme.ts
1039
- var SHADES = {
1040
- 50: { s: 1, l: 98 },
1041
- 100: { s: 1, l: 96 },
1042
- 200: { s: 1, l: 94 },
1043
- 300: { s: 2, l: 92 },
1044
- 500: { s: 5, l: 53 },
1045
- 600: { s: 7, l: 40 },
1046
- 700: { s: 9, l: 27 },
1047
- 800: { s: 12, l: 20 },
1048
- 1e3: { s: 20, l: 7 }
1049
- };
1050
- var COLORS = {
1051
- dark: {
1052
- h: 0,
1053
- s: 0,
1054
- l: 7
1055
- },
1056
- light: {
1057
- h: 0,
1058
- s: 0,
1059
- l: 100
1068
+ // src/hooks/useBankTransactions/utils.ts
1069
+ var collectAccounts = (transactions) => {
1070
+ const accounts = [];
1071
+ if (!transactions) {
1072
+ return accounts;
1060
1073
  }
1074
+ transactions.forEach((x) => {
1075
+ if (!accounts.find((y) => y.id === x.source_account_id)) {
1076
+ accounts.push({
1077
+ id: x.source_account_id,
1078
+ name: x.account_name || ""
1079
+ });
1080
+ }
1081
+ });
1082
+ return accounts.sort((a, b) => a.name.localeCompare(b.name));
1061
1083
  };
1062
-
1063
- // src/utils/colors.ts
1064
- var parseStylesFromThemeConfig = (theme) => {
1065
- let styles = {};
1066
- if (!theme) {
1067
- return styles;
1068
- }
1069
- if (theme.colors) {
1070
- const darkColor = parseColorFromTheme("dark", theme.colors.dark);
1071
- const lightColor = parseColorFromTheme("light", theme.colors.light);
1072
- const textColor = parseTextColorFromTheme(theme.colors.text);
1073
- styles = { ...styles, ...darkColor, ...lightColor, ...textColor };
1074
- }
1075
- return styles;
1084
+ var applyAmountFilter = (data, filter) => {
1085
+ return data?.filter((x) => {
1086
+ if ((filter?.min || filter?.min === 0) && (filter?.max || filter?.max === 0)) {
1087
+ return x.amount >= filter.min * 100 && x.amount <= filter.max * 100;
1088
+ }
1089
+ if (filter?.min || filter?.min === 0) {
1090
+ return x.amount >= filter.min * 100;
1091
+ }
1092
+ if (filter?.max || filter?.max === 0) {
1093
+ return x.amount <= filter.max * 100;
1094
+ }
1095
+ });
1076
1096
  };
1077
- var parseTextColorFromTheme = (color) => {
1078
- if (!color) {
1079
- return {};
1080
- }
1081
- try {
1082
- if ("hex" in color) {
1083
- return { "--text-color-primary": color.hex };
1097
+ var applyAccountFilter = (data, filter) => data?.filter((x) => filter && filter.includes(x.source_account_id));
1098
+
1099
+ // src/hooks/useBankTransactions/useBankTransactions.tsx
1100
+ import useSWRInfinite from "swr/infinite";
1101
+ var INITIAL_POLL_INTERVAL_MS = 1e3;
1102
+ var POLL_INTERVAL_AFTER_TXNS_RECEIVED_MS = 5e3;
1103
+ function useTriggerOnChange(data, anyAccountSyncing, callback) {
1104
+ const prevDataRef = useRef();
1105
+ useEffect3(() => {
1106
+ if (anyAccountSyncing && prevDataRef.current !== void 0 && prevDataRef.current !== data) {
1107
+ callback(data);
1084
1108
  }
1085
- return {};
1086
- } catch (_err) {
1087
- return {};
1088
- }
1109
+ prevDataRef.current = data;
1110
+ }, [data, anyAccountSyncing, callback]);
1111
+ }
1112
+ var filtersSettingString = (filters) => {
1113
+ 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()}` : ""}`;
1089
1114
  };
1090
- var parseColorFromTheme = (colorName, color) => {
1091
- if (!color) {
1092
- return {};
1093
- }
1094
- try {
1095
- if ("h" in color && "s" in color && "l" in color) {
1096
- return {
1097
- [`--color-${colorName}-h`]: color.h,
1098
- [`--color-${colorName}-s`]: color.s,
1099
- [`--color-${colorName}-l`]: color.l
1100
- };
1115
+ var useBankTransactions = (params) => {
1116
+ const {
1117
+ auth,
1118
+ businessId,
1119
+ apiUrl,
1120
+ addToast,
1121
+ touch,
1122
+ read,
1123
+ syncTimestamps,
1124
+ hasBeenTouched,
1125
+ eventCallbacks
1126
+ } = useLayerContext();
1127
+ const { scope = void 0 } = params ?? {};
1128
+ const [filters, setTheFilters] = useState5(
1129
+ scope ? { categorizationStatus: scope } : void 0
1130
+ );
1131
+ const display = useMemo2(() => {
1132
+ if (filters?.categorizationStatus === "review" /* review */) {
1133
+ return "review" /* review */;
1134
+ } else if (filters?.categorizationStatus === "all" /* all */) {
1135
+ return "all" /* all */;
1101
1136
  }
1102
- if ("r" in color && "g" in color && "b" in color) {
1103
- const { h, s, l } = rgbToHsl(color);
1104
- return {
1105
- [`--color-${colorName}-h`]: h,
1106
- [`--color-${colorName}-s`]: `${s}%`,
1107
- [`--color-${colorName}-l`]: `${l}%`
1108
- };
1137
+ return "categorized" /* categorized */;
1138
+ }, [filters?.categorizationStatus]);
1139
+ const [active, setActive] = useState5(false);
1140
+ const [loadingStatus, setLoadingStatus] = useState5("initial");
1141
+ const getKey = (index, prevData) => {
1142
+ if (!auth?.access_token || !active) {
1143
+ return [false, void 0];
1109
1144
  }
1110
- if ("hex" in color) {
1111
- const rgb = hexToRgb(color.hex);
1112
- if (!rgb) {
1113
- return {};
1145
+ if (index === 0) {
1146
+ return [
1147
+ businessId && auth?.access_token && `${filtersSettingString(filters)}-${businessId}`,
1148
+ void 0
1149
+ ];
1150
+ }
1151
+ return [
1152
+ businessId && auth?.access_token && `${filtersSettingString(filters)}-${businessId}-${prevData?.meta?.pagination?.cursor}`,
1153
+ prevData?.meta?.pagination?.cursor.toString()
1154
+ ];
1155
+ };
1156
+ const {
1157
+ data: rawResponseData,
1158
+ isLoading,
1159
+ isValidating,
1160
+ error: responseError,
1161
+ mutate,
1162
+ size,
1163
+ setSize
1164
+ } = useSWRInfinite(
1165
+ getKey,
1166
+ async ([_query, nextCursor]) => {
1167
+ if (auth?.access_token) {
1168
+ return Layer.getBankTransactions(apiUrl, auth?.access_token, {
1169
+ params: {
1170
+ businessId,
1171
+ cursor: nextCursor ?? "",
1172
+ categorized: filters?.categorizationStatus ? filters?.categorizationStatus === "categorized" /* categorized */ ? "true" : filters?.categorizationStatus === "review" /* review */ ? "false" : "" : "",
1173
+ direction: filters?.direction?.length === 1 ? filters.direction[0] === "CREDIT" /* CREDIT */ ? "INFLOW" : "OUTFLOW" : void 0,
1174
+ startDate: filters?.dateRange?.startDate?.toISOString() ?? void 0,
1175
+ endDate: filters?.dateRange?.endDate?.toISOString() ?? void 0
1176
+ }
1177
+ }).call(false);
1114
1178
  }
1115
- const { h, s, l } = rgbToHsl({
1116
- r: rgb.r.toString(),
1117
- g: rgb.g.toString(),
1118
- b: rgb.b.toString()
1119
- });
1120
- return {
1121
- [`--color-${colorName}-h`]: h,
1122
- [`--color-${colorName}-s`]: `${s}%`,
1123
- [`--color-${colorName}-l`]: `${l}%`
1124
- };
1179
+ return {};
1180
+ },
1181
+ {
1182
+ initialSize: 1,
1183
+ revalidateFirstPage: false
1125
1184
  }
1126
- return {};
1127
- } catch (_err) {
1128
- return {};
1129
- }
1130
- };
1131
- var parseColorFromThemeToHsl = (color) => {
1132
- if (!color) {
1133
- return;
1134
- }
1135
- try {
1136
- if ("h" in color && "s" in color && "l" in color) {
1137
- return {
1138
- h: Number(color.h),
1139
- s: Number(color.s),
1140
- l: Number(color.l)
1141
- };
1185
+ );
1186
+ const data = useMemo2(() => {
1187
+ if (rawResponseData && rawResponseData.length > 0) {
1188
+ return rawResponseData?.map((x) => x?.data).flat().filter((x) => !!x);
1142
1189
  }
1143
- if ("r" in color && "g" in color && "b" in color) {
1144
- const { h, s, l } = rgbToHsl(color);
1145
- return {
1146
- h,
1147
- s,
1148
- l
1149
- };
1190
+ return void 0;
1191
+ }, [rawResponseData]);
1192
+ const lastMetadata = useMemo2(() => {
1193
+ if (rawResponseData && rawResponseData.length > 0) {
1194
+ return rawResponseData[rawResponseData.length - 1].meta;
1150
1195
  }
1151
- if ("hex" in color) {
1152
- const rgb = hexToRgb(color.hex);
1153
- if (!rgb) {
1154
- return void 0;
1155
- }
1156
- const { h, s, l } = rgbToHsl({
1157
- r: rgb.r.toString(),
1158
- g: rgb.g.toString(),
1159
- b: rgb.b.toString()
1160
- });
1161
- return {
1162
- h,
1163
- s,
1164
- l
1165
- };
1196
+ return void 0;
1197
+ }, [rawResponseData]);
1198
+ const hasMore = useMemo2(() => {
1199
+ if (rawResponseData && rawResponseData.length > 0) {
1200
+ const lastElement = rawResponseData[rawResponseData.length - 1];
1201
+ return Boolean(
1202
+ lastElement.meta?.pagination?.cursor && lastElement.meta?.pagination?.has_more
1203
+ );
1166
1204
  }
1167
- return;
1168
- } catch (_err) {
1169
- return;
1170
- }
1171
- };
1172
- var rgbToHsl = (color) => {
1173
- let r = Number(color.r);
1174
- let g = Number(color.g);
1175
- let b = Number(color.b);
1176
- r /= 255;
1177
- g /= 255;
1178
- b /= 255;
1179
- const l = Math.max(r, g, b);
1180
- const s = l - Math.min(r, g, b);
1181
- const h = s ? l === r ? (g - b) / s : l === g ? 2 + (b - r) / s : 4 + (r - g) / s : 0;
1182
- return {
1183
- h: 60 * h < 0 ? 60 * h + 360 : 60 * h,
1184
- s: 100 * (s ? l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s)) : 0),
1185
- l: 100 * (2 * l - s) / 2
1186
- };
1187
- };
1188
- var hexToRgb = (hex) => {
1189
- const values = hex.replace(
1190
- /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
1191
- (m, r, g, b) => "#" + r + r + g + g + b + b
1192
- ).substring(1).match(/.{2}/g)?.map((x) => parseInt(x, 16));
1193
- if (!values) {
1194
- return;
1195
- }
1196
- return {
1197
- r: values[0],
1198
- g: values[1],
1199
- b: values[2]
1205
+ return false;
1206
+ }, [rawResponseData]);
1207
+ const accountsList = useMemo2(
1208
+ () => data ? collectAccounts(data) : [],
1209
+ [data]
1210
+ );
1211
+ useEffect3(() => {
1212
+ if (isLoading && loadingStatus === "initial") {
1213
+ setLoadingStatus("loading");
1214
+ return;
1215
+ }
1216
+ if (!isLoading && loadingStatus === "loading") {
1217
+ setLoadingStatus("complete");
1218
+ return;
1219
+ }
1220
+ }, [isLoading]);
1221
+ const activate = () => {
1222
+ setActive(true);
1200
1223
  };
1201
- };
1202
- var buildColorsPalette = (theme) => {
1203
- const darkColor = parseColorFromThemeToHsl(theme?.colors?.dark) ?? COLORS.dark;
1204
- const lightColor = parseColorFromThemeToHsl(theme?.colors?.light) ?? COLORS.light;
1205
- return {
1206
- 50: buildColorShade(50, darkColor),
1207
- 100: buildColorShade(100, darkColor),
1208
- 200: buildColorShade(200, darkColor),
1209
- 300: buildColorShade(300, darkColor),
1210
- 400: {
1211
- hsl: lightColor,
1212
- rgb: hslToRgb(lightColor),
1213
- hex: hslToHex(lightColor)
1214
- },
1215
- 500: buildColorShade(500, darkColor),
1216
- 600: buildColorShade(600, darkColor),
1217
- 700: buildColorShade(700, darkColor),
1218
- 800: buildColorShade(800, darkColor),
1219
- 900: {
1220
- hsl: darkColor,
1221
- rgb: hslToRgb(darkColor),
1222
- hex: hslToHex(darkColor)
1223
- },
1224
- 1e3: buildColorShade(1e3, darkColor)
1224
+ const setFilters = (value) => {
1225
+ setTheFilters({
1226
+ ...filters,
1227
+ ...value ?? {}
1228
+ });
1225
1229
  };
1226
- };
1227
- var buildColorShade = (shade, darkColorHsl) => {
1228
- const hsl = { h: darkColorHsl.h, ...SHADES[shade] };
1229
- const rgb = hslToRgb(hsl);
1230
- const hex = hslToHex(hsl);
1231
- return { hsl, rgb, hex };
1232
- };
1233
- var hueToRgb = (p, q, t) => {
1234
- if (t < 0)
1235
- t += 1;
1236
- if (t > 1)
1237
- t -= 1;
1238
- if (t < 1 / 6)
1239
- return p + (q - p) * 6 * t;
1240
- if (t < 1 / 2)
1241
- return q;
1242
- if (t < 2 / 3)
1243
- return p + (q - p) * (2 / 3 - t) * 6;
1244
- return p;
1245
- };
1246
- var hslToRgb = (hsl) => {
1247
- let r, g, b;
1248
- let l = hsl.l / 100;
1249
- let s = hsl.s / 100;
1250
- if (hsl.s === 0) {
1251
- r = g = b = l;
1252
- } else {
1253
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1254
- const p = 2 * l - q;
1255
- r = hueToRgb(p, q, hsl.h + 1 / 3);
1256
- g = hueToRgb(p, q, hsl.h);
1257
- b = hueToRgb(p, q, hsl.h - 1 / 3);
1258
- }
1259
- return {
1260
- r: Math.round(r * 255),
1261
- g: Math.round(g * 255),
1262
- b: Math.round(b * 255)
1230
+ const filteredData = useMemo2(() => {
1231
+ let filtered = data;
1232
+ if (!filtered) {
1233
+ return;
1234
+ }
1235
+ if (filters?.amount?.min || filters?.amount?.max) {
1236
+ filtered = applyAmountFilter(filtered, filters.amount);
1237
+ }
1238
+ if (filters?.account) {
1239
+ filtered = applyAccountFilter(filtered, filters.account);
1240
+ }
1241
+ return filtered;
1242
+ }, [filters, data]);
1243
+ const categorize = (id, newCategory, notify) => {
1244
+ const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
1245
+ if (foundBT) {
1246
+ updateOneLocal({ ...foundBT, processing: true, error: void 0 });
1247
+ }
1248
+ return Layer.categorizeBankTransaction(apiUrl, auth.access_token, {
1249
+ params: { businessId, bankTransactionId: id },
1250
+ body: newCategory
1251
+ }).then(({ data: newBT, errors }) => {
1252
+ if (newBT) {
1253
+ newBT.recently_categorized = true;
1254
+ updateOneLocal(newBT);
1255
+ }
1256
+ if (errors) {
1257
+ console.error(errors);
1258
+ throw errors;
1259
+ }
1260
+ if (newBT?.recently_categorized === true && notify) {
1261
+ addToast({ content: "Transaction saved" });
1262
+ }
1263
+ }).catch((err) => {
1264
+ const newBT = data?.find(
1265
+ (x) => x.business_id === businessId && x.id === id
1266
+ );
1267
+ if (newBT) {
1268
+ updateOneLocal({
1269
+ ...newBT,
1270
+ error: err.message,
1271
+ processing: false
1272
+ });
1273
+ }
1274
+ }).finally(() => {
1275
+ touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
1276
+ eventCallbacks?.onTransactionCategorized?.(id);
1277
+ });
1263
1278
  };
1264
- };
1265
- var hslToHex = (hsl) => {
1266
- const l = hsl.l / 100;
1267
- const s = hsl.s;
1268
- const a = s * Math.min(l, 1 - l) / 100;
1269
- const f = (n) => {
1270
- const k = (n + hsl.h / 30) % 12;
1271
- const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
1272
- return Math.round(255 * color).toString(16).padStart(2, "0");
1279
+ const match = (id, matchId, notify) => {
1280
+ const foundBT = data?.find((x) => x.business_id === businessId && x.id === id);
1281
+ if (foundBT) {
1282
+ updateOneLocal({ ...foundBT, processing: true, error: void 0 });
1283
+ }
1284
+ return Layer.matchBankTransaction(apiUrl, auth.access_token, {
1285
+ params: { businessId, bankTransactionId: id },
1286
+ body: { match_id: matchId, type: "Confirm_Match" /* CONFIRM_MATCH */ }
1287
+ }).then(({ data: bt, errors }) => {
1288
+ const newBT = data?.find(
1289
+ (x) => x.business_id === businessId && x.id === id
1290
+ );
1291
+ if (newBT) {
1292
+ newBT.recently_categorized = true;
1293
+ newBT.match = bt;
1294
+ newBT.categorization_status = "MATCHED" /* MATCHED */;
1295
+ updateOneLocal(newBT);
1296
+ }
1297
+ if (errors) {
1298
+ console.error(errors);
1299
+ throw errors;
1300
+ }
1301
+ if (newBT?.recently_categorized === true && notify) {
1302
+ addToast({ content: "Transaction saved" });
1303
+ }
1304
+ }).catch((err) => {
1305
+ const newBT = data?.find(
1306
+ (x) => x.business_id === businessId && x.id === id
1307
+ );
1308
+ if (newBT) {
1309
+ updateOneLocal({
1310
+ ...newBT,
1311
+ error: err.message,
1312
+ processing: false
1313
+ });
1314
+ }
1315
+ }).finally(() => {
1316
+ touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
1317
+ eventCallbacks?.onTransactionCategorized?.(id);
1318
+ });
1273
1319
  };
1274
- return `#${f(0)}${f(8)}${f(4)}`;
1275
- };
1276
-
1277
- // src/providers/LayerProvider/LayerProvider.tsx
1278
- import { add, isBefore } from "date-fns";
1279
- import useSWR, { SWRConfig } from "swr";
1280
- var reducer = (state, action) => {
1281
- switch (action.type) {
1282
- case "LayerContext.setAuth" /* setAuth */:
1283
- case "LayerContext.setBusiness" /* setBusiness */:
1284
- case "LayerContext.setCategories" /* setCategories */:
1285
- case "LayerContext.setTheme" /* setTheme */:
1286
- case "LayerContext.setOnboardingStep" /* setOnboardingStep */:
1287
- case "LayerContext.setColors" /* setColors */:
1288
- return { ...state, ...action.payload };
1289
- case "LayerContext.setToast" /* setToast */:
1290
- return {
1291
- ...state,
1292
- toasts: [
1293
- ...state.toasts,
1294
- { ...action.payload.toast, isExiting: false }
1295
- ]
1296
- };
1297
- case "LayerContext.setToastExit" /* setToastExit */:
1320
+ const updateOneLocal = (newBankTransaction) => {
1321
+ const updatedData = rawResponseData?.map((page) => {
1298
1322
  return {
1299
- ...state,
1300
- toasts: state.toasts.map(
1301
- (toast) => toast.id === action.payload.toast.id ? { ...toast, isExiting: false } : toast
1323
+ ...page,
1324
+ data: page.data?.map(
1325
+ (bt) => bt.id === newBankTransaction.id ? newBankTransaction : bt
1302
1326
  )
1303
1327
  };
1304
- case "LayerContext.removeToast" /* removeToast */:
1305
- return {
1306
- ...state,
1307
- toasts: state.toasts.filter((t) => t.id !== action.payload.toast.id)
1308
- };
1309
- default:
1310
- return state;
1311
- }
1312
- };
1313
- var LayerEnvironment = {
1314
- production: {
1315
- url: "https://auth.layerfi.com/oauth2/token",
1316
- scope: "https://api.layerfi.com/production",
1317
- apiUrl: "https://api.layerfi.com"
1318
- },
1319
- sandbox: {
1320
- url: "https://auth.layerfi.com/oauth2/token",
1321
- scope: "https://sandbox.layerfi.com/sandbox",
1322
- apiUrl: "https://sandbox.layerfi.com"
1323
- },
1324
- staging: {
1325
- url: "https://auth.layerfi.com/oauth2/token",
1326
- scope: "https://sandbox.layerfi.com/sandbox",
1327
- apiUrl: "https://sandbox.layerfi.com"
1328
- },
1329
- internalStaging: {
1330
- url: "https://auth.layerfi.com/oauth2/token",
1331
- scope: "https://sandbox.layerfi.com/sandbox",
1332
- apiUrl: "https://staging.layerfi.com"
1333
- }
1334
- };
1335
- var LayerProvider = ({
1336
- appId,
1337
- appSecret,
1338
- businessId,
1339
- children,
1340
- businessAccessToken,
1341
- environment = "production",
1342
- theme,
1343
- usePlaidSandbox,
1344
- onError,
1345
- eventCallbacks
1346
- }) => {
1347
- const defaultSWRConfig = {
1348
- revalidateInterval: 0,
1349
- revalidateOnFocus: false,
1350
- revalidateOnReconnect: false,
1351
- revalidateIfStale: false
1328
+ });
1329
+ mutate(updatedData, { revalidate: false });
1352
1330
  };
1353
- errorHandler.setOnError(onError);
1354
- const colors = buildColorsPalette(theme);
1355
- const { url, scope, apiUrl } = LayerEnvironment[environment];
1356
- const [state, dispatch] = useReducer(reducer, {
1357
- auth: {
1358
- access_token: "",
1359
- token_type: "",
1360
- expires_in: 0,
1361
- expires_at: new Date(2e3, 1, 1)
1362
- },
1363
- businessId,
1364
- business: void 0,
1365
- categories: [],
1366
- apiUrl,
1367
- theme,
1368
- colors,
1369
- usePlaidSandbox,
1370
- onboardingStep: void 0,
1371
- environment,
1372
- toasts: [],
1373
- eventCallbacks: {}
1374
- });
1375
- const { touch, syncTimestamps, read, readTimestamps, hasBeenTouched } = useDataSync();
1376
- const { data: auth } = appId !== void 0 && appSecret !== void 0 ? useSWR(
1377
- businessAccessToken === void 0 && appId !== void 0 && appSecret !== void 0 && isBefore(state.auth.expires_at, /* @__PURE__ */ new Date()) && "authenticate",
1378
- Layer.authenticate({
1379
- appId,
1380
- appSecret,
1381
- authenticationUrl: url,
1382
- scope
1383
- }),
1384
- defaultSWRConfig
1385
- ) : { data: void 0 };
1386
- useEffect3(() => {
1387
- if (businessAccessToken) {
1388
- dispatch({
1389
- type: "LayerContext.setAuth" /* setAuth */,
1390
- payload: {
1391
- auth: {
1392
- access_token: businessAccessToken,
1393
- token_type: "Bearer",
1394
- expires_in: 3600,
1395
- expires_at: add(/* @__PURE__ */ new Date(), { seconds: 3600 })
1396
- }
1397
- }
1398
- });
1399
- } else if (auth?.access_token) {
1400
- dispatch({
1401
- type: "LayerContext.setAuth" /* setAuth */,
1402
- payload: {
1403
- auth: {
1404
- ...auth,
1405
- expires_at: add(/* @__PURE__ */ new Date(), { seconds: auth.expires_in })
1406
- }
1407
- }
1331
+ const shouldHideAfterCategorize = (bankTransaction) => {
1332
+ return filters?.categorizationStatus === "review" /* review */ && ReviewCategories.includes(bankTransaction.categorization_status);
1333
+ };
1334
+ const removeAfterCategorize = (bankTransaction) => {
1335
+ if (shouldHideAfterCategorize(bankTransaction)) {
1336
+ const updatedData = rawResponseData?.map((page) => {
1337
+ return {
1338
+ ...page,
1339
+ data: page.data?.filter((bt) => bt.id !== bankTransaction.id)
1340
+ };
1408
1341
  });
1342
+ mutate(updatedData, { revalidate: false });
1409
1343
  }
1410
- }, [businessAccessToken, auth?.access_token]);
1411
- const { data: categoriesData } = useSWR(
1412
- businessId && state.auth?.access_token && `categories-${businessId}`,
1413
- Layer.getCategories(apiUrl, state.auth?.access_token, {
1414
- params: { businessId }
1415
- }),
1416
- {
1417
- ...defaultSWRConfig,
1418
- onSuccess: (response) => {
1419
- if (response?.data?.categories?.length) {
1420
- dispatch({
1421
- type: "LayerContext.setCategories" /* setCategories */,
1422
- payload: { categories: response.data.categories || [] }
1423
- });
1424
- }
1425
- }
1344
+ };
1345
+ const refetch = () => {
1346
+ mutate();
1347
+ };
1348
+ const fetchMore = () => {
1349
+ if (hasMore) {
1350
+ setSize(size + 1);
1426
1351
  }
1427
- );
1352
+ };
1353
+ const getCacheKey = (txnFilters) => {
1354
+ return filtersSettingString(txnFilters);
1355
+ };
1428
1356
  useEffect3(() => {
1429
- if (categoriesData?.data?.categories?.length) {
1430
- dispatch({
1431
- type: "LayerContext.setCategories" /* setCategories */,
1432
- payload: { categories: categoriesData.data.categories || [] }
1433
- });
1357
+ if (isLoading || isValidating) {
1358
+ read("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */, getCacheKey(filters));
1434
1359
  }
1435
- }, [categoriesData]);
1436
- const { data: businessData } = useSWR(
1437
- businessId && state?.auth?.access_token && `business-${businessId}`,
1438
- Layer.getBusiness(apiUrl, state?.auth?.access_token, {
1439
- params: { businessId }
1440
- }),
1441
- {
1442
- ...defaultSWRConfig,
1443
- onSuccess: (response) => {
1444
- if (response?.data) {
1445
- dispatch({
1446
- type: "LayerContext.setBusiness" /* setBusiness */,
1447
- payload: { business: response.data || [] }
1448
- });
1449
- }
1450
- }
1360
+ }, [isLoading, isValidating]);
1361
+ useEffect3(() => {
1362
+ if (hasBeenTouched(getCacheKey(filters))) {
1363
+ refetch();
1451
1364
  }
1365
+ }, [syncTimestamps, filters]);
1366
+ const { data: linkedAccounts, refetchAccounts } = useLinkedAccounts();
1367
+ const anyAccountSyncing = useMemo2(
1368
+ () => Boolean(linkedAccounts?.some((item) => item.is_syncing)),
1369
+ [linkedAccounts]
1452
1370
  );
1371
+ const [pollIntervalMs, setPollIntervalMs] = useState5(INITIAL_POLL_INTERVAL_MS);
1372
+ const transactionsNotSynced = useMemo2(
1373
+ () => loadingStatus === "complete" && anyAccountSyncing && (!data || data?.length === 0),
1374
+ [data, anyAccountSyncing, loadingStatus]
1375
+ );
1376
+ let intervalId = void 0;
1377
+ const [refreshTrigger, setRefreshTrigger] = useState5(-1);
1453
1378
  useEffect3(() => {
1454
- if (businessData?.data) {
1455
- dispatch({
1456
- type: "LayerContext.setBusiness" /* setBusiness */,
1457
- payload: { business: businessData.data || [] }
1458
- });
1379
+ if (refreshTrigger !== -1) {
1380
+ refetch();
1381
+ refetchAccounts();
1459
1382
  }
1460
- }, [businessData]);
1461
- const setTheme = (theme2) => {
1462
- dispatch({
1463
- type: "LayerContext.setTheme" /* setTheme */,
1464
- payload: { theme: theme2 }
1465
- });
1466
- dispatch({
1467
- type: "LayerContext.setColors" /* setColors */,
1468
- payload: { colors: buildColorsPalette(theme2) }
1469
- });
1470
- };
1471
- const setLightColor = (color) => {
1472
- setTheme({
1473
- ...state.theme ?? {},
1474
- colors: {
1475
- ...state.theme?.colors ?? {},
1476
- light: color
1477
- }
1478
- });
1479
- };
1480
- const setDarkColor = (color) => {
1481
- setTheme({
1482
- ...state.theme ?? {},
1483
- colors: {
1484
- ...state.theme?.colors ?? {},
1485
- dark: color
1383
+ }, [refreshTrigger]);
1384
+ useEffect3(() => {
1385
+ if (anyAccountSyncing) {
1386
+ intervalId = setInterval(() => {
1387
+ setRefreshTrigger(Math.random());
1388
+ }, pollIntervalMs);
1389
+ } else {
1390
+ if (intervalId) {
1391
+ clearInterval(intervalId);
1486
1392
  }
1487
- });
1488
- };
1489
- const setTextColor = (color) => {
1490
- setTheme({
1491
- ...state.theme ?? {},
1492
- colors: {
1493
- ...state.theme?.colors ?? {},
1494
- text: color
1393
+ }
1394
+ return () => {
1395
+ if (intervalId) {
1396
+ clearInterval(intervalId);
1495
1397
  }
1496
- });
1497
- };
1498
- const setToast = (toast) => {
1499
- dispatch({ type: "LayerContext.setToast" /* setToast */, payload: { toast } });
1500
- };
1501
- const removeToast = (toast) => {
1502
- dispatch({ type: "LayerContext.removeToast" /* removeToast */, payload: { toast } });
1503
- };
1504
- const setToastExit = (toast) => {
1505
- dispatch({ type: "LayerContext.setToastExit" /* setToastExit */, payload: { toast } });
1506
- };
1507
- const addToast = (toast) => {
1508
- const id = `${Date.now()}-${Math.random()}`;
1509
- const newToast = { id, isExiting: false, ...toast };
1510
- setToast(newToast);
1511
- setTimeout(() => {
1512
- removeToast(newToast);
1513
- setTimeout(() => {
1514
- setToastExit(newToast);
1515
- }, 1e3);
1516
- }, toast.duration || 2e3);
1517
- };
1518
- const setColors = (colors2) => setTheme({
1519
- ...state.theme ?? {},
1520
- colors: colors2
1398
+ };
1399
+ }, [anyAccountSyncing, transactionsNotSynced, pollIntervalMs]);
1400
+ useTriggerOnChange(data, anyAccountSyncing, (newTransactionList) => {
1401
+ clearInterval(intervalId);
1402
+ setPollIntervalMs(POLL_INTERVAL_AFTER_TXNS_RECEIVED_MS);
1403
+ touch("BANK_TRANSACTIONS" /* BANK_TRANSACTIONS */);
1521
1404
  });
1522
- const getColor = (shade) => {
1523
- if (state.colors && shade in state.colors) {
1524
- return state.colors[shade];
1525
- }
1526
- return;
1405
+ return {
1406
+ data: filteredData,
1407
+ metadata: lastMetadata,
1408
+ loadingStatus,
1409
+ isLoading,
1410
+ isValidating,
1411
+ refetch,
1412
+ error: responseError,
1413
+ categorize,
1414
+ match,
1415
+ updateOneLocal,
1416
+ shouldHideAfterCategorize,
1417
+ removeAfterCategorize,
1418
+ filters,
1419
+ setFilters,
1420
+ accountsList,
1421
+ activate,
1422
+ display,
1423
+ fetchMore,
1424
+ hasMore
1527
1425
  };
1528
- const setOnboardingStep = (value) => dispatch({
1529
- type: "LayerContext.setOnboardingStep" /* setOnboardingStep */,
1530
- payload: { onboardingStep: value }
1531
- });
1532
- const drawerContextData = useDrawer();
1533
- return /* @__PURE__ */ React7.createElement(SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ React7.createElement(
1534
- LayerContext.Provider,
1535
- {
1536
- value: {
1537
- ...state,
1538
- setTheme,
1539
- getColor,
1540
- setLightColor,
1541
- setDarkColor,
1542
- setTextColor,
1543
- setColors,
1544
- setOnboardingStep,
1545
- addToast,
1546
- removeToast,
1547
- onError: errorHandler.onError,
1548
- touch,
1549
- read,
1550
- syncTimestamps,
1551
- readTimestamps,
1552
- hasBeenTouched,
1553
- eventCallbacks
1554
- }
1555
- },
1556
- /* @__PURE__ */ React7.createElement(BankTransactionsProvider, null, /* @__PURE__ */ React7.createElement(DrawerContext.Provider, { value: drawerContextData }, children, /* @__PURE__ */ React7.createElement(GlobalWidgets, null)))
1557
- ));
1558
1426
  };
1559
1427
 
1560
- // src/components/Onboarding/Onboarding.tsx
1561
- import React44, { useContext as useContext6, useEffect as useEffect6, useState as useState8 } from "react";
1428
+ // src/providers/BankTransactionsProvider/BankTransactionsProvider.tsx
1429
+ var BankTransactionsProvider = ({
1430
+ children
1431
+ }) => {
1432
+ const bankTransactionsContextData = useBankTransactions();
1433
+ return /* @__PURE__ */ React6.createElement(BankTransactionsContext.Provider, { value: bankTransactionsContextData }, children);
1434
+ };
1562
1435
 
1563
- // src/contexts/LinkedAccountsContext/LinkedAccountsContext.ts
1564
- import { createContext as createContext4 } from "react";
1565
- var LinkedAccountsContext = createContext4({
1566
- data: void 0,
1567
- isLoading: false,
1568
- loadingStatus: "initial",
1569
- isValidating: false,
1570
- error: void 0,
1571
- updateConnectionStatus: () => {
1572
- },
1573
- addConnection: () => {
1574
- },
1575
- removeConnection: () => {
1576
- },
1577
- repairConnection: () => {
1578
- },
1579
- refetchAccounts: () => {
1580
- },
1581
- unlinkAccount: () => {
1582
- },
1583
- denyAccount: () => {
1584
- },
1585
- confirmAccount: () => {
1586
- },
1587
- breakConnection: () => {
1436
+ // src/config/theme.ts
1437
+ var SHADES = {
1438
+ 50: { s: 1, l: 98 },
1439
+ 100: { s: 1, l: 96 },
1440
+ 200: { s: 1, l: 94 },
1441
+ 300: { s: 2, l: 92 },
1442
+ 500: { s: 5, l: 53 },
1443
+ 600: { s: 7, l: 40 },
1444
+ 700: { s: 9, l: 27 },
1445
+ 800: { s: 12, l: 20 },
1446
+ 1e3: { s: 20, l: 7 }
1447
+ };
1448
+ var COLORS = {
1449
+ dark: {
1450
+ h: 0,
1451
+ s: 0,
1452
+ l: 7
1588
1453
  },
1589
- syncAccounts: () => {
1454
+ light: {
1455
+ h: 0,
1456
+ s: 0,
1457
+ l: 100
1590
1458
  }
1591
- });
1592
-
1593
- // src/providers/LinkedAccountsProvider/LinkedAccountsProvider.tsx
1594
- import React8 from "react";
1595
-
1596
- // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
1597
- import { useEffect as useEffect4, useState as useState5 } from "react";
1598
- import { usePlaidLink } from "react-plaid-link";
1459
+ };
1599
1460
 
1600
- // src/hooks/useLinkedAccounts/mockData.ts
1601
- var LINKED_ACCOUNTS_MOCK_DATA = [
1602
- {
1603
- id: "d800ada8-8075-4436-a712-08efabcbd51a",
1604
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1605
- external_account_source: "PLAID",
1606
- external_account_name: "Citi Double Cash\xAE Card",
1607
- mask: "1234",
1608
- latest_balance_timestamp: {
1609
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1610
- external_account_source: "PLAID",
1611
- balance: 435121,
1612
- at: "2024-04-03T13:00:00Z",
1613
- created_at: "2024-04-06T22:47:59.715458Z"
1614
- },
1615
- current_ledger_balance: 373717,
1616
- institution: {
1617
- name: "Chase",
1618
- logo: ""
1619
- },
1620
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1621
- connection_external_id: "11111",
1622
- connection_needs_repair_as_of: null,
1623
- requires_user_confirmation_as_of: null,
1624
- is_syncing: true
1625
- },
1626
- {
1627
- id: "f98ec50a-c370-484d-a35b-d00207436075",
1628
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1629
- external_account_source: "PLAID",
1630
- external_account_name: "Citi Double Cash\xAE Card",
1631
- mask: "1234",
1632
- latest_balance_timestamp: {
1633
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1634
- external_account_source: "PLAID",
1635
- balance: 435121,
1636
- at: "2024-04-03T13:00:00Z",
1637
- created_at: "2024-04-06T16:44:35.715458Z"
1638
- },
1639
- current_ledger_balance: 373717,
1640
- institution: {
1641
- name: "Chase",
1642
- logo: ""
1643
- },
1644
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1645
- connection_external_id: "11111",
1646
- connection_needs_repair_as_of: null,
1647
- requires_user_confirmation_as_of: null,
1648
- is_syncing: false
1649
- },
1650
- {
1651
- id: "843f1748-fdaa-422d-a73d-2489a40c8dc7",
1652
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1653
- external_account_source: "PLAID",
1654
- external_account_name: "Citi Double Cash\xAE Card",
1655
- mask: "1234",
1656
- latest_balance_timestamp: {
1657
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1658
- external_account_source: "PLAID",
1659
- balance: 435121,
1660
- at: "2024-04-03T13:00:00Z",
1661
- created_at: "2024-04-06T16:44:35.715458Z"
1662
- },
1663
- current_ledger_balance: 373717,
1664
- institution: {
1665
- name: "Chase",
1666
- logo: ""
1667
- },
1668
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1669
- connection_external_id: "11111",
1670
- connection_needs_repair_as_of: "2024-03-06T16:44:35.715458Z",
1671
- requires_user_confirmation_as_of: null,
1672
- is_syncing: false
1673
- },
1674
- {
1675
- id: "8f430e29-e339-4d71-a08a-fce469c7a7c1",
1676
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1677
- external_account_source: "PLAID",
1678
- external_account_name: "Citi Double Cash\xAE Card",
1679
- mask: "1234",
1680
- latest_balance_timestamp: {
1681
- external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1682
- external_account_source: "PLAID",
1683
- balance: 435121,
1684
- at: "2024-04-03T13:00:00Z",
1685
- created_at: "2024-04-06T16:44:35.715458Z"
1461
+ // src/utils/colors.ts
1462
+ var parseStylesFromThemeConfig = (theme) => {
1463
+ let styles = {};
1464
+ if (!theme) {
1465
+ return styles;
1466
+ }
1467
+ if (theme.colors) {
1468
+ const darkColor = parseColorFromTheme("dark", theme.colors.dark);
1469
+ const lightColor = parseColorFromTheme("light", theme.colors.light);
1470
+ const textColor = parseTextColorFromTheme(theme.colors.text);
1471
+ styles = { ...styles, ...darkColor, ...lightColor, ...textColor };
1472
+ }
1473
+ return styles;
1474
+ };
1475
+ var parseTextColorFromTheme = (color) => {
1476
+ if (!color) {
1477
+ return {};
1478
+ }
1479
+ try {
1480
+ if ("hex" in color) {
1481
+ return { "--text-color-primary": color.hex };
1482
+ }
1483
+ return {};
1484
+ } catch (_err) {
1485
+ return {};
1486
+ }
1487
+ };
1488
+ var parseColorFromTheme = (colorName, color) => {
1489
+ if (!color) {
1490
+ return {};
1491
+ }
1492
+ try {
1493
+ if ("h" in color && "s" in color && "l" in color) {
1494
+ return {
1495
+ [`--color-${colorName}-h`]: color.h,
1496
+ [`--color-${colorName}-s`]: color.s,
1497
+ [`--color-${colorName}-l`]: color.l
1498
+ };
1499
+ }
1500
+ if ("r" in color && "g" in color && "b" in color) {
1501
+ const { h, s, l } = rgbToHsl(color);
1502
+ return {
1503
+ [`--color-${colorName}-h`]: h,
1504
+ [`--color-${colorName}-s`]: `${s}%`,
1505
+ [`--color-${colorName}-l`]: `${l}%`
1506
+ };
1507
+ }
1508
+ if ("hex" in color) {
1509
+ const rgb = hexToRgb(color.hex);
1510
+ if (!rgb) {
1511
+ return {};
1512
+ }
1513
+ const { h, s, l } = rgbToHsl({
1514
+ r: rgb.r.toString(),
1515
+ g: rgb.g.toString(),
1516
+ b: rgb.b.toString()
1517
+ });
1518
+ return {
1519
+ [`--color-${colorName}-h`]: h,
1520
+ [`--color-${colorName}-s`]: `${s}%`,
1521
+ [`--color-${colorName}-l`]: `${l}%`
1522
+ };
1523
+ }
1524
+ return {};
1525
+ } catch (_err) {
1526
+ return {};
1527
+ }
1528
+ };
1529
+ var parseColorFromThemeToHsl = (color) => {
1530
+ if (!color) {
1531
+ return;
1532
+ }
1533
+ try {
1534
+ if ("h" in color && "s" in color && "l" in color) {
1535
+ return {
1536
+ h: Number(color.h),
1537
+ s: Number(color.s),
1538
+ l: Number(color.l)
1539
+ };
1540
+ }
1541
+ if ("r" in color && "g" in color && "b" in color) {
1542
+ const { h, s, l } = rgbToHsl(color);
1543
+ return {
1544
+ h,
1545
+ s,
1546
+ l
1547
+ };
1548
+ }
1549
+ if ("hex" in color) {
1550
+ const rgb = hexToRgb(color.hex);
1551
+ if (!rgb) {
1552
+ return void 0;
1553
+ }
1554
+ const { h, s, l } = rgbToHsl({
1555
+ r: rgb.r.toString(),
1556
+ g: rgb.g.toString(),
1557
+ b: rgb.b.toString()
1558
+ });
1559
+ return {
1560
+ h,
1561
+ s,
1562
+ l
1563
+ };
1564
+ }
1565
+ return;
1566
+ } catch (_err) {
1567
+ return;
1568
+ }
1569
+ };
1570
+ var rgbToHsl = (color) => {
1571
+ let r = Number(color.r);
1572
+ let g = Number(color.g);
1573
+ let b = Number(color.b);
1574
+ r /= 255;
1575
+ g /= 255;
1576
+ b /= 255;
1577
+ const l = Math.max(r, g, b);
1578
+ const s = l - Math.min(r, g, b);
1579
+ const h = s ? l === r ? (g - b) / s : l === g ? 2 + (b - r) / s : 4 + (r - g) / s : 0;
1580
+ return {
1581
+ h: 60 * h < 0 ? 60 * h + 360 : 60 * h,
1582
+ s: 100 * (s ? l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s)) : 0),
1583
+ l: 100 * (2 * l - s) / 2
1584
+ };
1585
+ };
1586
+ var hexToRgb = (hex) => {
1587
+ const values = hex.replace(
1588
+ /^#?([a-f\d])([a-f\d])([a-f\d])$/i,
1589
+ (m, r, g, b) => "#" + r + r + g + g + b + b
1590
+ ).substring(1).match(/.{2}/g)?.map((x) => parseInt(x, 16));
1591
+ if (!values) {
1592
+ return;
1593
+ }
1594
+ return {
1595
+ r: values[0],
1596
+ g: values[1],
1597
+ b: values[2]
1598
+ };
1599
+ };
1600
+ var buildColorsPalette = (theme) => {
1601
+ const darkColor = parseColorFromThemeToHsl(theme?.colors?.dark) ?? COLORS.dark;
1602
+ const lightColor = parseColorFromThemeToHsl(theme?.colors?.light) ?? COLORS.light;
1603
+ return {
1604
+ 50: buildColorShade(50, darkColor),
1605
+ 100: buildColorShade(100, darkColor),
1606
+ 200: buildColorShade(200, darkColor),
1607
+ 300: buildColorShade(300, darkColor),
1608
+ 400: {
1609
+ hsl: lightColor,
1610
+ rgb: hslToRgb(lightColor),
1611
+ hex: hslToHex(lightColor)
1686
1612
  },
1687
- current_ledger_balance: 373717,
1688
- institution: {
1689
- name: "Chase",
1690
- logo: ""
1613
+ 500: buildColorShade(500, darkColor),
1614
+ 600: buildColorShade(600, darkColor),
1615
+ 700: buildColorShade(700, darkColor),
1616
+ 800: buildColorShade(800, darkColor),
1617
+ 900: {
1618
+ hsl: darkColor,
1619
+ rgb: hslToRgb(darkColor),
1620
+ hex: hslToHex(darkColor)
1691
1621
  },
1692
- connection_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
1693
- connection_external_id: "11111",
1694
- connection_needs_repair_as_of: null,
1695
- requires_user_confirmation_as_of: "2024-03-06T16:44:35.715458Z",
1696
- is_syncing: false
1622
+ 1e3: buildColorShade(1e3, darkColor)
1623
+ };
1624
+ };
1625
+ var buildColorShade = (shade, darkColorHsl) => {
1626
+ const hsl = { h: darkColorHsl.h, ...SHADES[shade] };
1627
+ const rgb = hslToRgb(hsl);
1628
+ const hex = hslToHex(hsl);
1629
+ return { hsl, rgb, hex };
1630
+ };
1631
+ var hueToRgb = (p, q, t) => {
1632
+ if (t < 0)
1633
+ t += 1;
1634
+ if (t > 1)
1635
+ t -= 1;
1636
+ if (t < 1 / 6)
1637
+ return p + (q - p) * 6 * t;
1638
+ if (t < 1 / 2)
1639
+ return q;
1640
+ if (t < 2 / 3)
1641
+ return p + (q - p) * (2 / 3 - t) * 6;
1642
+ return p;
1643
+ };
1644
+ var hslToRgb = (hsl) => {
1645
+ let r, g, b;
1646
+ let l = hsl.l / 100;
1647
+ let s = hsl.s / 100;
1648
+ if (hsl.s === 0) {
1649
+ r = g = b = l;
1650
+ } else {
1651
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1652
+ const p = 2 * l - q;
1653
+ r = hueToRgb(p, q, hsl.h + 1 / 3);
1654
+ g = hueToRgb(p, q, hsl.h);
1655
+ b = hueToRgb(p, q, hsl.h - 1 / 3);
1656
+ }
1657
+ return {
1658
+ r: Math.round(r * 255),
1659
+ g: Math.round(g * 255),
1660
+ b: Math.round(b * 255)
1661
+ };
1662
+ };
1663
+ var hslToHex = (hsl) => {
1664
+ const l = hsl.l / 100;
1665
+ const s = hsl.s;
1666
+ const a = s * Math.min(l, 1 - l) / 100;
1667
+ const f = (n) => {
1668
+ const k = (n + hsl.h / 30) % 12;
1669
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
1670
+ return Math.round(255 * color).toString(16).padStart(2, "0");
1671
+ };
1672
+ return `#${f(0)}${f(8)}${f(4)}`;
1673
+ };
1674
+
1675
+ // src/providers/LayerProvider/LayerProvider.tsx
1676
+ import { add, isBefore } from "date-fns";
1677
+ import useSWR2, { SWRConfig } from "swr";
1678
+ var reducer = (state, action) => {
1679
+ switch (action.type) {
1680
+ case "LayerContext.setAuth" /* setAuth */:
1681
+ case "LayerContext.setBusiness" /* setBusiness */:
1682
+ case "LayerContext.setCategories" /* setCategories */:
1683
+ case "LayerContext.setTheme" /* setTheme */:
1684
+ case "LayerContext.setOnboardingStep" /* setOnboardingStep */:
1685
+ case "LayerContext.setColors" /* setColors */:
1686
+ return { ...state, ...action.payload };
1687
+ case "LayerContext.setToast" /* setToast */:
1688
+ return {
1689
+ ...state,
1690
+ toasts: [
1691
+ ...state.toasts,
1692
+ { ...action.payload.toast, isExiting: false }
1693
+ ]
1694
+ };
1695
+ case "LayerContext.setToastExit" /* setToastExit */:
1696
+ return {
1697
+ ...state,
1698
+ toasts: state.toasts.map(
1699
+ (toast) => toast.id === action.payload.toast.id ? { ...toast, isExiting: false } : toast
1700
+ )
1701
+ };
1702
+ case "LayerContext.removeToast" /* removeToast */:
1703
+ return {
1704
+ ...state,
1705
+ toasts: state.toasts.filter((t) => t.id !== action.payload.toast.id)
1706
+ };
1707
+ default:
1708
+ return state;
1697
1709
  }
1698
- ];
1699
-
1700
- // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
1701
- import useSWR2 from "swr";
1702
- var DEBUG = true;
1703
- var USE_MOCK_RESPONSE_DATA = false;
1704
- var useLinkedAccounts = () => {
1705
- const {
1706
- auth,
1710
+ };
1711
+ var LayerEnvironment = {
1712
+ production: {
1713
+ url: "https://auth.layerfi.com/oauth2/token",
1714
+ scope: "https://api.layerfi.com/production",
1715
+ apiUrl: "https://api.layerfi.com"
1716
+ },
1717
+ sandbox: {
1718
+ url: "https://auth.layerfi.com/oauth2/token",
1719
+ scope: "https://sandbox.layerfi.com/sandbox",
1720
+ apiUrl: "https://sandbox.layerfi.com"
1721
+ },
1722
+ staging: {
1723
+ url: "https://auth.layerfi.com/oauth2/token",
1724
+ scope: "https://sandbox.layerfi.com/sandbox",
1725
+ apiUrl: "https://sandbox.layerfi.com"
1726
+ },
1727
+ internalStaging: {
1728
+ url: "https://auth.layerfi.com/oauth2/token",
1729
+ scope: "https://sandbox.layerfi.com/sandbox",
1730
+ apiUrl: "https://staging.layerfi.com"
1731
+ }
1732
+ };
1733
+ var LayerProvider = ({
1734
+ appId,
1735
+ appSecret,
1736
+ businessId,
1737
+ children,
1738
+ businessAccessToken,
1739
+ environment = "production",
1740
+ theme,
1741
+ usePlaidSandbox,
1742
+ onError,
1743
+ eventCallbacks
1744
+ }) => {
1745
+ const defaultSWRConfig = {
1746
+ revalidateInterval: 0,
1747
+ revalidateOnFocus: false,
1748
+ revalidateOnReconnect: false,
1749
+ revalidateIfStale: false
1750
+ };
1751
+ errorHandler.setOnError(onError);
1752
+ const colors = buildColorsPalette(theme);
1753
+ const { url, scope, apiUrl } = LayerEnvironment[environment];
1754
+ const [state, dispatch] = useReducer(reducer, {
1755
+ auth: {
1756
+ access_token: "",
1757
+ token_type: "",
1758
+ expires_in: 0,
1759
+ expires_at: new Date(2e3, 1, 1)
1760
+ },
1707
1761
  businessId,
1762
+ business: void 0,
1763
+ categories: [],
1708
1764
  apiUrl,
1765
+ theme,
1766
+ colors,
1709
1767
  usePlaidSandbox,
1768
+ onboardingStep: void 0,
1769
+ environment,
1770
+ toasts: [],
1771
+ eventCallbacks: {}
1772
+ });
1773
+ const {
1710
1774
  touch,
1711
- read,
1712
1775
  syncTimestamps,
1713
- hasBeenTouched
1714
- } = useLayerContext();
1715
- const [linkToken, setLinkToken] = useState5(null);
1716
- const [loadingStatus, setLoadingStatus] = useState5("initial");
1717
- const USE_PLAID_SANDBOX = usePlaidSandbox ?? true;
1718
- const [linkMode, setLinkMode] = useState5("add");
1719
- const queryKey = businessId && auth?.access_token && `linked-accounts-${businessId}`;
1720
- const {
1721
- data: responseData,
1722
- isLoading,
1723
- isValidating,
1724
- error: responseError,
1725
- mutate
1726
- } = useSWR2(
1727
- queryKey,
1728
- Layer.getLinkedAccounts(apiUrl, auth?.access_token, {
1729
- params: { businessId }
1730
- })
1731
- );
1732
- useEffect4(() => {
1733
- if (!isLoading && responseData?.data.external_accounts) {
1734
- setLoadingStatus("complete");
1735
- return;
1736
- }
1737
- if (isLoading && loadingStatus === "initial") {
1738
- setLoadingStatus("loading");
1739
- return;
1740
- }
1741
- if (!isLoading && loadingStatus === "loading") {
1742
- setLoadingStatus("complete");
1743
- }
1744
- }, [isLoading]);
1745
- const fetchPlaidLinkToken = async () => {
1746
- if (auth?.access_token) {
1747
- const linkToken2 = (await Layer.getPlaidLinkToken(apiUrl, auth.access_token, {
1748
- params: { businessId }
1749
- })).data.link_token;
1750
- setLinkMode("add");
1751
- setLinkToken(linkToken2);
1752
- }
1753
- };
1754
- const fetchPlaidUpdateModeLinkToken = async (plaidItemPlaidId) => {
1755
- if (auth?.access_token) {
1756
- const linkToken2 = (await Layer.getPlaidUpdateModeLinkToken(apiUrl, auth.access_token, {
1757
- params: { businessId },
1758
- body: { plaid_item_id: plaidItemPlaidId }
1759
- })).data.link_token;
1760
- setLinkMode("update");
1761
- setLinkToken(linkToken2);
1762
- }
1763
- };
1764
- const exchangePlaidPublicToken2 = async (publicToken, metadata) => {
1765
- await Layer.exchangePlaidPublicToken(apiUrl, auth?.access_token, {
1766
- params: { businessId },
1767
- body: { public_token: publicToken, institution: metadata.institution }
1768
- });
1769
- refetchAccounts();
1770
- };
1771
- const { open: plaidLinkStart, ready: plaidLinkReady } = usePlaidLink({
1772
- token: linkToken,
1773
- // If in update mode, we don't need to exchange the public token for an access token.
1774
- // The existing access token will automatically become valid again
1775
- onSuccess: async (publicToken, metadata) => {
1776
- if (linkMode == "add") {
1777
- exchangePlaidPublicToken2(publicToken, metadata);
1778
- } else {
1779
- await updateConnectionStatus2();
1780
- refetchAccounts();
1781
- setLinkMode("add");
1782
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1783
- }
1784
- },
1785
- onExit: () => setLinkMode("add"),
1786
- env: USE_PLAID_SANDBOX ? "sandbox" : void 0
1787
- });
1776
+ read,
1777
+ readTimestamps,
1778
+ hasBeenTouched,
1779
+ resetCaches
1780
+ } = useDataSync();
1781
+ const { data: auth } = appId !== void 0 && appSecret !== void 0 ? useSWR2(
1782
+ businessAccessToken === void 0 && appId !== void 0 && appSecret !== void 0 && isBefore(state.auth.expires_at, /* @__PURE__ */ new Date()) && "authenticate",
1783
+ Layer.authenticate({
1784
+ appId,
1785
+ appSecret,
1786
+ authenticationUrl: url,
1787
+ scope
1788
+ }),
1789
+ defaultSWRConfig
1790
+ ) : { data: void 0 };
1788
1791
  useEffect4(() => {
1789
- if (plaidLinkReady) {
1790
- plaidLinkStart();
1791
- }
1792
- }, [plaidLinkStart, plaidLinkReady]);
1793
- const mockResponseData = {
1794
- data: LINKED_ACCOUNTS_MOCK_DATA,
1795
- meta: {},
1796
- error: void 0
1797
- };
1798
- const addConnection = (source) => {
1799
- if (source === "PLAID") {
1800
- fetchPlaidLinkToken();
1801
- } else {
1802
- console.error(
1803
- `Adding a connection with source ${source} not yet supported`
1804
- );
1805
- }
1806
- };
1807
- const repairConnection = async (source, connectionExternalId) => {
1808
- if (source === "PLAID") {
1809
- await fetchPlaidUpdateModeLinkToken(connectionExternalId);
1810
- } else {
1811
- console.error(
1812
- `Repairing a connection with source ${source} not yet supported`
1813
- );
1814
- }
1815
- };
1816
- const removeConnection = async (source, connectionExternalId) => {
1817
- if (source === "PLAID") {
1818
- await unlinkPlaidItem2(connectionExternalId);
1819
- await refetchAccounts();
1820
- } else {
1821
- console.error(
1822
- `Removing a connection with source ${source} not yet supported`
1823
- );
1824
- }
1825
- };
1826
- const unlinkAccount2 = async (source, accountId) => {
1827
- DEBUG && console.log("unlinking account");
1828
- if (source === "PLAID") {
1829
- await Layer.unlinkAccount(apiUrl, auth?.access_token, {
1830
- params: { businessId, accountId }
1792
+ if (businessAccessToken) {
1793
+ dispatch({
1794
+ type: "LayerContext.setAuth" /* setAuth */,
1795
+ payload: {
1796
+ auth: {
1797
+ access_token: businessAccessToken,
1798
+ token_type: "Bearer",
1799
+ expires_in: 3600,
1800
+ expires_at: add(/* @__PURE__ */ new Date(), { seconds: 3600 })
1801
+ }
1802
+ }
1831
1803
  });
1832
- await refetchAccounts();
1833
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1834
- } else {
1835
- console.error(
1836
- `Unlinking an account with source ${source} not yet supported`
1837
- );
1838
- }
1839
- };
1840
- const confirmAccount = async (source, accountId) => {
1841
- DEBUG && console.log("confirming account");
1842
- if (source === "PLAID") {
1843
- await Layer.confirmConnection(apiUrl, auth?.access_token, {
1844
- params: {
1845
- businessId,
1846
- accountId
1804
+ } else if (auth?.access_token) {
1805
+ dispatch({
1806
+ type: "LayerContext.setAuth" /* setAuth */,
1807
+ payload: {
1808
+ auth: {
1809
+ ...auth,
1810
+ expires_at: add(/* @__PURE__ */ new Date(), { seconds: auth.expires_in })
1811
+ }
1847
1812
  }
1848
1813
  });
1849
- await refetchAccounts();
1850
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1851
- } else {
1852
- console.error(
1853
- `Confirming an account with source ${source} not yet supported`
1854
- );
1855
1814
  }
1856
- };
1857
- const denyAccount = async (source, accountId) => {
1858
- DEBUG && console.log("confirming account");
1859
- if (source === "PLAID") {
1860
- await Layer.denyConnection(apiUrl, auth?.access_token, {
1861
- params: {
1862
- businessId,
1863
- accountId
1815
+ }, [businessAccessToken, auth?.access_token]);
1816
+ const { data: categoriesData } = useSWR2(
1817
+ businessId && state.auth?.access_token && `categories-${businessId}`,
1818
+ Layer.getCategories(apiUrl, state.auth?.access_token, {
1819
+ params: { businessId }
1820
+ }),
1821
+ {
1822
+ ...defaultSWRConfig,
1823
+ onSuccess: (response) => {
1824
+ if (response?.data?.categories?.length) {
1825
+ dispatch({
1826
+ type: "LayerContext.setCategories" /* setCategories */,
1827
+ payload: { categories: response.data.categories || [] }
1828
+ });
1864
1829
  }
1830
+ }
1831
+ }
1832
+ );
1833
+ useEffect4(() => {
1834
+ if (categoriesData?.data?.categories?.length) {
1835
+ dispatch({
1836
+ type: "LayerContext.setCategories" /* setCategories */,
1837
+ payload: { categories: categoriesData.data.categories || [] }
1865
1838
  });
1866
- await refetchAccounts();
1867
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1868
- } else {
1869
- console.error(
1870
- `Denying an account with source ${source} not yet supported`
1871
- );
1872
1839
  }
1873
- };
1874
- const breakConnection = async (source, connectionExternalId) => {
1875
- DEBUG && console.log("Breaking sandbox plaid item connection");
1876
- if (source === "PLAID") {
1877
- await Layer.breakPlaidItemConnection(apiUrl, auth?.access_token, {
1878
- params: {
1879
- businessId,
1880
- plaidItemPlaidId: connectionExternalId
1840
+ }, [categoriesData]);
1841
+ const { data: businessData } = useSWR2(
1842
+ businessId && state?.auth?.access_token && `business-${businessId}`,
1843
+ Layer.getBusiness(apiUrl, state?.auth?.access_token, {
1844
+ params: { businessId }
1845
+ }),
1846
+ {
1847
+ ...defaultSWRConfig,
1848
+ onSuccess: (response) => {
1849
+ if (response?.data) {
1850
+ dispatch({
1851
+ type: "LayerContext.setBusiness" /* setBusiness */,
1852
+ payload: { business: response.data || [] }
1853
+ });
1881
1854
  }
1855
+ }
1856
+ }
1857
+ );
1858
+ useEffect4(() => {
1859
+ if (businessData?.data) {
1860
+ dispatch({
1861
+ type: "LayerContext.setBusiness" /* setBusiness */,
1862
+ payload: { business: businessData.data || [] }
1882
1863
  });
1883
- await refetchAccounts();
1884
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1885
- } else {
1886
- console.error(
1887
- `Breaking a sandbox connection with source ${source} not yet supported`
1888
- );
1889
1864
  }
1865
+ }, [businessData]);
1866
+ const setTheme = (theme2) => {
1867
+ dispatch({
1868
+ type: "LayerContext.setTheme" /* setTheme */,
1869
+ payload: { theme: theme2 }
1870
+ });
1871
+ dispatch({
1872
+ type: "LayerContext.setColors" /* setColors */,
1873
+ payload: { colors: buildColorsPalette(theme2) }
1874
+ });
1890
1875
  };
1891
- const refetchAccounts = async () => {
1892
- DEBUG && console.log("refetching accounts...");
1893
- await mutate();
1894
- };
1895
- const syncAccounts = async () => {
1896
- DEBUG && console.log("resyncing accounts...");
1897
- await Layer.syncConnection(apiUrl, auth?.access_token, {
1898
- params: { businessId }
1876
+ const setLightColor = (color) => {
1877
+ setTheme({
1878
+ ...state.theme ?? {},
1879
+ colors: {
1880
+ ...state.theme?.colors ?? {},
1881
+ light: color
1882
+ }
1899
1883
  });
1900
1884
  };
1901
- const updateConnectionStatus2 = async () => {
1902
- DEBUG && console.log("updating connection status...");
1903
- await Layer.updateConnectionStatus(apiUrl, auth?.access_token, {
1904
- params: { businessId }
1885
+ const setDarkColor = (color) => {
1886
+ setTheme({
1887
+ ...state.theme ?? {},
1888
+ colors: {
1889
+ ...state.theme?.colors ?? {},
1890
+ dark: color
1891
+ }
1905
1892
  });
1906
1893
  };
1907
- const unlinkPlaidItem2 = async (plaidItemPlaidId) => {
1908
- DEBUG && console.log("unlinking plaid item");
1909
- await Layer.unlinkPlaidItem(apiUrl, auth?.access_token, {
1910
- params: { businessId, plaidItemPlaidId }
1894
+ const setTextColor = (color) => {
1895
+ setTheme({
1896
+ ...state.theme ?? {},
1897
+ colors: {
1898
+ ...state.theme?.colors ?? {},
1899
+ text: color
1900
+ }
1911
1901
  });
1912
- await refetchAccounts();
1913
- touch("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */);
1914
1902
  };
1915
- useEffect4(() => {
1916
- if (queryKey && (isLoading || isValidating)) {
1917
- read("LINKED_ACCOUNTS" /* LINKED_ACCOUNTS */, queryKey);
1918
- }
1919
- }, [isLoading, isValidating]);
1920
- useEffect4(() => {
1921
- if (queryKey && hasBeenTouched(queryKey)) {
1922
- refetchAccounts();
1903
+ const setToast = (toast) => {
1904
+ dispatch({ type: "LayerContext.setToast" /* setToast */, payload: { toast } });
1905
+ };
1906
+ const removeToast = (toast) => {
1907
+ dispatch({ type: "LayerContext.removeToast" /* removeToast */, payload: { toast } });
1908
+ };
1909
+ const setToastExit = (toast) => {
1910
+ dispatch({ type: "LayerContext.setToastExit" /* setToastExit */, payload: { toast } });
1911
+ };
1912
+ const addToast = (toast) => {
1913
+ const id = `${Date.now()}-${Math.random()}`;
1914
+ const newToast = { id, isExiting: false, ...toast };
1915
+ setToast(newToast);
1916
+ setTimeout(() => {
1917
+ removeToast(newToast);
1918
+ setTimeout(() => {
1919
+ setToastExit(newToast);
1920
+ }, 1e3);
1921
+ }, toast.duration || 2e3);
1922
+ };
1923
+ const setColors = (colors2) => setTheme({
1924
+ ...state.theme ?? {},
1925
+ colors: colors2
1926
+ });
1927
+ const getColor = (shade) => {
1928
+ if (state.colors && shade in state.colors) {
1929
+ return state.colors[shade];
1923
1930
  }
1924
- }, [syncTimestamps]);
1925
- return {
1926
- data: USE_MOCK_RESPONSE_DATA ? mockResponseData.data : responseData?.data.external_accounts,
1927
- isLoading,
1928
- loadingStatus,
1929
- isValidating,
1930
- error: responseError,
1931
- addConnection,
1932
- removeConnection,
1933
- repairConnection,
1934
- refetchAccounts,
1935
- unlinkAccount: unlinkAccount2,
1936
- confirmAccount,
1937
- denyAccount,
1938
- breakConnection,
1939
- syncAccounts,
1940
- updateConnectionStatus: updateConnectionStatus2
1931
+ return;
1941
1932
  };
1933
+ const setOnboardingStep = (value) => dispatch({
1934
+ type: "LayerContext.setOnboardingStep" /* setOnboardingStep */,
1935
+ payload: { onboardingStep: value }
1936
+ });
1937
+ const drawerContextData = useDrawer();
1938
+ return /* @__PURE__ */ React7.createElement(SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ React7.createElement(
1939
+ LayerContext.Provider,
1940
+ {
1941
+ value: {
1942
+ ...state,
1943
+ setTheme,
1944
+ getColor,
1945
+ setLightColor,
1946
+ setDarkColor,
1947
+ setTextColor,
1948
+ setColors,
1949
+ setOnboardingStep,
1950
+ addToast,
1951
+ removeToast,
1952
+ onError: errorHandler.onError,
1953
+ touch,
1954
+ read,
1955
+ syncTimestamps,
1956
+ readTimestamps,
1957
+ expireDataCaches: resetCaches,
1958
+ hasBeenTouched,
1959
+ eventCallbacks
1960
+ }
1961
+ },
1962
+ /* @__PURE__ */ React7.createElement(BankTransactionsProvider, null, /* @__PURE__ */ React7.createElement(DrawerContext.Provider, { value: drawerContextData }, children, /* @__PURE__ */ React7.createElement(GlobalWidgets, null)))
1963
+ ));
1942
1964
  };
1943
1965
 
1966
+ // src/components/Onboarding/Onboarding.tsx
1967
+ import React44, { useContext as useContext6, useEffect as useEffect6, useState as useState8 } from "react";
1968
+
1969
+ // src/contexts/LinkedAccountsContext/LinkedAccountsContext.ts
1970
+ import { createContext as createContext4 } from "react";
1971
+ var LinkedAccountsContext = createContext4({
1972
+ data: void 0,
1973
+ isLoading: false,
1974
+ loadingStatus: "initial",
1975
+ isValidating: false,
1976
+ error: void 0,
1977
+ updateConnectionStatus: () => {
1978
+ },
1979
+ addConnection: () => {
1980
+ },
1981
+ removeConnection: () => {
1982
+ },
1983
+ repairConnection: () => {
1984
+ },
1985
+ refetchAccounts: () => {
1986
+ },
1987
+ unlinkAccount: () => {
1988
+ },
1989
+ denyAccount: () => {
1990
+ },
1991
+ confirmAccount: () => {
1992
+ },
1993
+ breakConnection: () => {
1994
+ },
1995
+ syncAccounts: () => {
1996
+ }
1997
+ });
1998
+
1944
1999
  // src/providers/LinkedAccountsProvider/LinkedAccountsProvider.tsx
2000
+ import React8 from "react";
1945
2001
  var LinkedAccountsProvider = ({
1946
2002
  children
1947
2003
  }) => {
@@ -2215,8 +2271,20 @@ var Sunrise = ({ size = 12, ...props }) => /* @__PURE__ */ React16.createElement
2215
2271
  );
2216
2272
  var Sunrise_default = Sunrise;
2217
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
+
2218
2286
  // src/utils/bankTransactions.ts
2219
- import { isWithinInterval, parseISO as parseISO2 } from "date-fns";
2287
+ import { isWithinInterval, parseISO } from "date-fns";
2220
2288
  var hasMatch = (bankTransaction) => {
2221
2289
  return Boolean(
2222
2290
  bankTransaction?.suggested_matches && bankTransaction?.suggested_matches?.length > 0 || bankTransaction?.match
@@ -2244,7 +2312,7 @@ var countTransactionsToReview = ({
2244
2312
  };
2245
2313
  return transactions.filter((tx) => {
2246
2314
  try {
2247
- return filterVisibility("review" /* review */, tx) && isWithinInterval(parseISO2(tx.date), dateRangeInterval);
2315
+ return filterVisibility("review" /* review */, tx) && isWithinInterval(parseISO(tx.date), dateRangeInterval);
2248
2316
  } catch (_err) {
2249
2317
  return false;
2250
2318
  }
@@ -2301,7 +2369,7 @@ var ChevronRight = ({ size = 18, ...props }) => /* @__PURE__ */ React17.createEl
2301
2369
  var ChevronRight_default = ChevronRight;
2302
2370
 
2303
2371
  // src/components/Button/Button.tsx
2304
- import React18, { useRef } from "react";
2372
+ import React18, { useRef as useRef2 } from "react";
2305
2373
  import classNames4 from "classnames";
2306
2374
  var Button = ({
2307
2375
  className,
@@ -2315,7 +2383,7 @@ var Button = ({
2315
2383
  fullWidth,
2316
2384
  ...props
2317
2385
  }) => {
2318
- const buttonRef = useRef(null);
2386
+ const buttonRef = useRef2(null);
2319
2387
  let justifyContent = "center";
2320
2388
  if (justify) {
2321
2389
  justifyContent = justify;
@@ -2986,7 +3054,7 @@ var ExpandButton = ({
2986
3054
 
2987
3055
  // src/components/Button/Link.tsx
2988
3056
  import React35, {
2989
- useRef as useRef4
3057
+ useRef as useRef5
2990
3058
  } from "react";
2991
3059
  import classNames12 from "classnames";
2992
3060
  var Link2 = ({
@@ -3001,7 +3069,7 @@ var Link2 = ({
3001
3069
  fullWidth,
3002
3070
  ...props
3003
3071
  }) => {
3004
- const linkRef = useRef4(null);
3072
+ const linkRef = useRef5(null);
3005
3073
  let justifyContent = "center";
3006
3074
  if (justify) {
3007
3075
  justifyContent = justify;
@@ -3059,7 +3127,7 @@ var Link2 = ({
3059
3127
  };
3060
3128
 
3061
3129
  // src/components/Typography/Text.tsx
3062
- 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";
3063
3131
  import classNames13 from "classnames";
3064
3132
  var Text = ({
3065
3133
  as: Component2 = "p",
@@ -3100,7 +3168,7 @@ var TextWithTooltip = ({
3100
3168
  tooltipOptions,
3101
3169
  ...props
3102
3170
  }) => {
3103
- const textElementRef = useRef5();
3171
+ const textElementRef = useRef6();
3104
3172
  const compareSize = () => {
3105
3173
  if (textElementRef.current) {
3106
3174
  const compare = textElementRef.current.children[0].scrollWidth > textElementRef.current.children[0].clientWidth;
@@ -3557,11 +3625,11 @@ var MoreVertical = ({ size = 18, ...props }) => {
3557
3625
  var MoreVertical_default = MoreVertical;
3558
3626
 
3559
3627
  // src/components/HoverMenu/HoverMenu.tsx
3560
- 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";
3561
3629
  import classNames17 from "classnames";
3562
3630
  var HoverMenu = ({ children, config }) => {
3563
3631
  const [openMenu, setOpenMenu] = useState9(false);
3564
- const hoverMenuRef = useRef6(null);
3632
+ const hoverMenuRef = useRef7(null);
3565
3633
  const hoverMenuClassName = classNames17(
3566
3634
  "Layer__hover-menu",
3567
3635
  openMenu && "Layer__hover-menu--open"
@@ -4201,12 +4269,12 @@ var LinkedAccountsComponent = ({
4201
4269
  };
4202
4270
 
4203
4271
  // src/components/BankTransactions/BankTransactions.tsx
4204
- import React109, { useState as useState25, useMemo as useMemo6, useEffect as useEffect19 } from "react";
4272
+ import React109, { useEffect as useEffect19, useMemo as useMemo6, useState as useState25 } from "react";
4205
4273
 
4206
4274
  // src/hooks/useElementSize/useElementSize.ts
4207
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef7 } from "react";
4275
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef8 } from "react";
4208
4276
  var useElementSize = (callback) => {
4209
- const ref = useRef7(null);
4277
+ const ref = useRef8(null);
4210
4278
  useLayoutEffect2(() => {
4211
4279
  const element = ref?.current;
4212
4280
  if (!element) {
@@ -4247,7 +4315,7 @@ var debounce = (fnc, timeout = 300) => {
4247
4315
  import React85 from "react";
4248
4316
 
4249
4317
  // src/components/BankTransactionList/BankTransactionListItem.tsx
4250
- 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";
4251
4319
 
4252
4320
  // src/icons/ChevronDownFill.tsx
4253
4321
  import * as React57 from "react";
@@ -4275,7 +4343,7 @@ var ChevronDownFill = ({ size = 18, ...props }) => /* @__PURE__ */ React57.creat
4275
4343
  var ChevronDownFill_default = ChevronDownFill;
4276
4344
 
4277
4345
  // src/components/BankTransactionRow/BankTransactionRow.tsx
4278
- 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";
4279
4347
 
4280
4348
  // src/icons/Scissors.tsx
4281
4349
  import * as React58 from "react";
@@ -4693,7 +4761,7 @@ var CategorySelectDrawerContent = ({
4693
4761
 
4694
4762
  // src/components/CategorySelect/CategorySelect.tsx
4695
4763
  import classNames23 from "classnames";
4696
- import { parseISO as parseISO3, format as formatTime } from "date-fns";
4764
+ import { parseISO as parseISO2, format as formatTime } from "date-fns";
4697
4765
  var mapCategoryToOption2 = (category) => {
4698
4766
  return {
4699
4767
  type: "category" /* CATEGORY */,
@@ -4745,7 +4813,7 @@ var Option2 = (props) => {
4745
4813
  ...props,
4746
4814
  className: `${props.className} Layer__select__option-content__match`
4747
4815
  },
4748
- /* @__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)),
4749
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)))
4750
4818
  );
4751
4819
  }
@@ -4875,7 +4943,7 @@ import React80, {
4875
4943
  useState as useState13,
4876
4944
  useCallback,
4877
4945
  useEffect as useEffect10,
4878
- useRef as useRef9
4946
+ useRef as useRef10
4879
4947
  } from "react";
4880
4948
 
4881
4949
  // src/icons/ScissorsFullOpen.tsx
@@ -5037,7 +5105,7 @@ var InputGroup = ({
5037
5105
  };
5038
5106
 
5039
5107
  // src/components/Input/FileInput.tsx
5040
- import React71, { useRef as useRef8 } from "react";
5108
+ import React71, { useRef as useRef9 } from "react";
5041
5109
 
5042
5110
  // src/icons/UploadCloud.tsx
5043
5111
  import * as React70 from "react";
@@ -5092,7 +5160,7 @@ var UploadCloud_default = UploadCloud;
5092
5160
 
5093
5161
  // src/components/Input/FileInput.tsx
5094
5162
  var FileInput = ({ text = "Upload", onUpload }) => {
5095
- const hiddenFileInput = useRef8(null);
5163
+ const hiddenFileInput = useRef9(null);
5096
5164
  const onClick = () => {
5097
5165
  if (hiddenFileInput.current) {
5098
5166
  hiddenFileInput.current.click();
@@ -5193,7 +5261,7 @@ import React75 from "react";
5193
5261
 
5194
5262
  // src/components/BankTransactionRow/MatchBadge.tsx
5195
5263
  import React74 from "react";
5196
- import { parseISO as parseISO4, format as formatTime2 } from "date-fns";
5264
+ import { parseISO as parseISO3, format as formatTime2 } from "date-fns";
5197
5265
  var MatchBadge = ({
5198
5266
  bankTransaction,
5199
5267
  classNamePrefix,
@@ -5206,7 +5274,7 @@ var MatchBadge = ({
5206
5274
  Badge,
5207
5275
  {
5208
5276
  icon: /* @__PURE__ */ React74.createElement(MinimizeTwo_default, { size: 11 }),
5209
- 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)))
5210
5278
  },
5211
5279
  text
5212
5280
  );
@@ -5216,7 +5284,7 @@ var MatchBadge = ({
5216
5284
 
5217
5285
  // src/components/MatchForm/MatchForm.tsx
5218
5286
  import classNames28 from "classnames";
5219
- import { parseISO as parseISO5, format as formatTime3 } from "date-fns";
5287
+ import { parseISO as parseISO4, format as formatTime3 } from "date-fns";
5220
5288
  var MatchForm = ({
5221
5289
  classNamePrefix,
5222
5290
  bankTransaction,
@@ -5255,7 +5323,7 @@ var MatchForm = ({
5255
5323
  {
5256
5324
  className: `Layer__nowrap ${classNamePrefix}__match-table__date`
5257
5325
  },
5258
- /* @__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)),
5259
5327
  /* @__PURE__ */ React75.createElement("span", { className: "amount-next-to-date" }, "$", centsToDollars(match.details.amount))
5260
5328
  ),
5261
5329
  /* @__PURE__ */ React75.createElement("div", { className: `${classNamePrefix}__match-table__desc` }, /* @__PURE__ */ React75.createElement(
@@ -5298,7 +5366,7 @@ var MatchForm = ({
5298
5366
  // src/components/MatchForm/MatchFormMobile.tsx
5299
5367
  import React76 from "react";
5300
5368
  import classNames29 from "classnames";
5301
- import { parseISO as parseISO6, format as formatTime4 } from "date-fns";
5369
+ import { parseISO as parseISO5, format as formatTime4 } from "date-fns";
5302
5370
  var MatchFormMobile = ({
5303
5371
  classNamePrefix,
5304
5372
  bankTransaction,
@@ -5345,7 +5413,7 @@ var MatchFormMobile = ({
5345
5413
  size: "sm" /* sm */,
5346
5414
  as: "span"
5347
5415
  },
5348
- formatTime4(parseISO6(match.details.date), MONTH_DAY_FORMAT)
5416
+ formatTime4(parseISO5(match.details.date), MONTH_DAY_FORMAT)
5349
5417
  ))),
5350
5418
  /* @__PURE__ */ React76.createElement("div", { className: `${classNamePrefix}__match-item__col-status` }, selectedMatchId && selectedMatchId === match.id ? /* @__PURE__ */ React76.createElement(
5351
5419
  Check_default,
@@ -5674,7 +5742,7 @@ var ExpandedBankTransactionRow = forwardRef5(
5674
5742
  const [splitFormError, setSplitFormError] = useState13();
5675
5743
  const [height, setHeight] = useState13(0);
5676
5744
  const [isOver, setOver] = useState13(false);
5677
- const bodyRef = useRef9(null);
5745
+ const bodyRef = useRef10(null);
5678
5746
  const [memoText, setMemoText] = useState13();
5679
5747
  const [receiptUrls, setReceiptUrls] = useState13([]);
5680
5748
  const [isLoaded, setIsLoaded] = useState13(false);
@@ -5773,7 +5841,6 @@ var ExpandedBankTransactionRow = forwardRef5(
5773
5841
  setSplitFormError(void 0);
5774
5842
  };
5775
5843
  const save = async () => {
5776
- const endpoint = `/v1/businesses/${businessId}/bank-transactions/${bankTransaction.id}/metadata`;
5777
5844
  if (showDescriptions && memoText != void 0) {
5778
5845
  const result = await Layer.updateBankTransactionMetadata(
5779
5846
  apiUrl,
@@ -6145,7 +6212,7 @@ var SplitTooltipDetails = ({
6145
6212
 
6146
6213
  // src/components/BankTransactionRow/BankTransactionRow.tsx
6147
6214
  import classNames33 from "classnames";
6148
- import { parseISO as parseISO7, format as formatTime5 } from "date-fns";
6215
+ import { parseISO as parseISO6, format as formatTime5 } from "date-fns";
6149
6216
  var extractDescriptionForSplit = (category) => {
6150
6217
  if (!category.entries) {
6151
6218
  return "";
@@ -6177,12 +6244,12 @@ var BankTransactionRow = ({
6177
6244
  showReceiptUploads,
6178
6245
  stringOverrides
6179
6246
  }) => {
6180
- const expandedRowRef = useRef10(null);
6247
+ const expandedRowRef = useRef11(null);
6181
6248
  const [showRetry, setShowRetry] = useState14(false);
6182
6249
  const {
6183
- filters,
6184
6250
  categorize: categorizeBankTransaction2,
6185
- match: matchBankTransaction2
6251
+ match: matchBankTransaction2,
6252
+ shouldHideAfterCategorize
6186
6253
  } = useBankTransactionsContext();
6187
6254
  const [selectedCategory, setSelectedCategory] = useState14(
6188
6255
  getDefaultSelectedCategory(bankTransaction)
@@ -6220,7 +6287,7 @@ var BankTransactionRow = ({
6220
6287
  }
6221
6288
  }, [bankTransaction.error]);
6222
6289
  useEffect11(() => {
6223
- if (editable && bankTransaction.recently_categorized) {
6290
+ if (editable && bankTransaction.recently_categorized && shouldHideAfterCategorize(bankTransaction)) {
6224
6291
  setTimeout(() => {
6225
6292
  removeTransaction(bankTransaction);
6226
6293
  }, 300);
@@ -6253,7 +6320,7 @@ var BankTransactionRow = ({
6253
6320
  const openClassName = open ? `${className}--expanded` : "";
6254
6321
  const rowClassName = classNames33(
6255
6322
  className,
6256
- bankTransaction.recently_categorized && editable ? "Layer__bank-transaction-row--removing" : "",
6323
+ bankTransaction.recently_categorized && editable && shouldHideAfterCategorize(bankTransaction) ? "Layer__bank-transaction-row--removing" : "",
6257
6324
  open ? openClassName : "",
6258
6325
  initialLoad ? "initial-load" : "",
6259
6326
  showComponent ? "show" : ""
@@ -6264,7 +6331,7 @@ var BankTransactionRow = ({
6264
6331
  className: "Layer__table-cell Layer__bank-transaction-table__date-col",
6265
6332
  ...openRow
6266
6333
  },
6267
- /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, formatTime5(parseISO7(bankTransaction.date), dateFormat))
6334
+ /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, formatTime5(parseISO6(bankTransaction.date), dateFormat))
6268
6335
  ), /* @__PURE__ */ React82.createElement(
6269
6336
  "td",
6270
6337
  {
@@ -6354,7 +6421,7 @@ var BankTransactionRow = ({
6354
6421
  dateFormat
6355
6422
  }
6356
6423
  ), /* @__PURE__ */ React82.createElement("span", { className: `${className}__category-text__text` }, `${formatTime5(
6357
- parseISO7(bankTransaction.match.bank_transaction.date),
6424
+ parseISO6(bankTransaction.match.bank_transaction.date),
6358
6425
  dateFormat
6359
6426
  )}, ${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,
6360
6427
  !categorized && !open && showRetry ? /* @__PURE__ */ React82.createElement(
@@ -6429,7 +6496,7 @@ var BankTransactionRow = ({
6429
6496
 
6430
6497
  // src/components/BankTransactionList/Assignment.tsx
6431
6498
  import React83 from "react";
6432
- import { parseISO as parseISO8, format as formatTime6 } from "date-fns";
6499
+ import { parseISO as parseISO7, format as formatTime6 } from "date-fns";
6433
6500
  var Assignment = ({ bankTransaction }) => {
6434
6501
  if (bankTransaction.match && bankTransaction.categorization_status === "MATCHED" /* MATCHED */) {
6435
6502
  return /* @__PURE__ */ React83.createElement(React83.Fragment, null, /* @__PURE__ */ React83.createElement(
@@ -6441,7 +6508,7 @@ var Assignment = ({ bankTransaction }) => {
6441
6508
  text: "Matched"
6442
6509
  }
6443
6510
  ), /* @__PURE__ */ React83.createElement(Text, { className: "Layer__bank-transaction-list-item__category-text__text" }, `${formatTime6(
6444
- parseISO8(bankTransaction.match.bank_transaction.date),
6511
+ parseISO7(bankTransaction.match.bank_transaction.date),
6445
6512
  DATE_FORMAT
6446
6513
  )}, ${bankTransaction.match.bank_transaction.description ?? bankTransaction.match?.details?.description}`));
6447
6514
  }
@@ -6466,7 +6533,7 @@ var Assignment = ({ bankTransaction }) => {
6466
6533
 
6467
6534
  // src/components/BankTransactionList/BankTransactionListItem.tsx
6468
6535
  import classNames34 from "classnames";
6469
- import { parseISO as parseISO9, format as formatTime7 } from "date-fns";
6536
+ import { parseISO as parseISO8, format as formatTime7 } from "date-fns";
6470
6537
  var BankTransactionListItem = ({
6471
6538
  index = 0,
6472
6539
  dateFormat,
@@ -6479,9 +6546,13 @@ var BankTransactionListItem = ({
6479
6546
  removeTransaction,
6480
6547
  stringOverrides
6481
6548
  }) => {
6482
- const expandedRowRef = useRef11(null);
6549
+ const expandedRowRef = useRef12(null);
6483
6550
  const [showRetry, setShowRetry] = useState15(false);
6484
- const { categorize: categorizeBankTransaction2, match: matchBankTransaction2 } = useBankTransactionsContext();
6551
+ const {
6552
+ categorize: categorizeBankTransaction2,
6553
+ match: matchBankTransaction2,
6554
+ shouldHideAfterCategorize
6555
+ } = useBankTransactionsContext();
6485
6556
  const [selectedCategory, setSelectedCategory] = useState15(
6486
6557
  getDefaultSelectedCategory(bankTransaction)
6487
6558
  );
@@ -6503,7 +6574,7 @@ var BankTransactionListItem = ({
6503
6574
  }
6504
6575
  }, [bankTransaction.error]);
6505
6576
  useEffect12(() => {
6506
- if (editable && bankTransaction.recently_categorized) {
6577
+ if (editable && bankTransaction.recently_categorized && shouldHideAfterCategorize(bankTransaction)) {
6507
6578
  setTimeout(() => {
6508
6579
  removeTransaction(bankTransaction);
6509
6580
  }, 300);
@@ -6531,11 +6602,11 @@ var BankTransactionListItem = ({
6531
6602
  const openClassName = open ? `${className}--expanded` : "";
6532
6603
  const rowClassName = classNames34(
6533
6604
  className,
6534
- bankTransaction.recently_categorized && editable ? "Layer__bank-transaction-row--removing" : "",
6605
+ bankTransaction.recently_categorized && editable && shouldHideAfterCategorize(bankTransaction) ? "Layer__bank-transaction-row--removing" : "",
6535
6606
  open ? openClassName : "",
6536
6607
  showComponent ? "show" : ""
6537
6608
  );
6538
- 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(
6609
+ 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(
6539
6610
  "div",
6540
6611
  {
6541
6612
  onClick: toggleOpen,
@@ -6645,7 +6716,7 @@ var BankTransactionList = ({
6645
6716
  import React93 from "react";
6646
6717
 
6647
6718
  // src/components/BankTransactionMobileList/BankTransactionMobileListItem.tsx
6648
- import React92, { useContext as useContext11, useEffect as useEffect17, useRef as useRef12, useState as useState22 } from "react";
6719
+ import React92, { useContext as useContext11, useEffect as useEffect17, useRef as useRef13, useState as useState22 } from "react";
6649
6720
 
6650
6721
  // src/components/BankTransactionMobileList/BankTransactionMobileForms.tsx
6651
6722
  import React91 from "react";
@@ -7102,7 +7173,7 @@ var TransactionToOpenContext = createContext5({
7102
7173
 
7103
7174
  // src/components/BankTransactionMobileList/BankTransactionMobileListItem.tsx
7104
7175
  import classNames36 from "classnames";
7105
- import { parseISO as parseISO10, format as formatTime8 } from "date-fns";
7176
+ import { parseISO as parseISO9, format as formatTime8 } from "date-fns";
7106
7177
  var DATE_FORMAT2 = "LLL d";
7107
7178
  var getAssignedValue2 = (bankTransaction) => {
7108
7179
  if (bankTransaction.categorization_status === "SPLIT" /* SPLIT */) {
@@ -7127,13 +7198,14 @@ var BankTransactionMobileListItem = ({
7127
7198
  setTransactionIdToOpen,
7128
7199
  clearTransactionIdToOpen
7129
7200
  } = useContext11(TransactionToOpenContext);
7201
+ const { shouldHideAfterCategorize } = useBankTransactionsContext();
7130
7202
  const formRowRef = useElementSize(
7131
7203
  (_a, _b, { height: height2 }) => setHeight(height2)
7132
7204
  );
7133
7205
  const headingRowRef = useElementSize((_a, _b, { height: height2 }) => {
7134
7206
  setHeadingHeight(height2);
7135
7207
  });
7136
- const itemRef = useRef12(null);
7208
+ const itemRef = useRef13(null);
7137
7209
  const [removeAnim, setRemoveAnim] = useState22(false);
7138
7210
  const [purpose, setPurpose] = useState22(
7139
7211
  bankTransaction.category ? bankTransaction.categorization_status === "SPLIT" /* SPLIT */ ? "more" /* more */ : "business" /* business */ : hasMatch(bankTransaction) ? "more" /* more */ : "business" /* business */
@@ -7160,7 +7232,7 @@ var BankTransactionMobileListItem = ({
7160
7232
  }, [transactionIdToOpen]);
7161
7233
  useEffect17(() => {
7162
7234
  if (!removeAnim && bankTransaction.recently_categorized) {
7163
- if (editable) {
7235
+ if (editable && shouldHideAfterCategorize(bankTransaction)) {
7164
7236
  setRemoveAnim(true);
7165
7237
  openNext();
7166
7238
  } else {
@@ -7193,7 +7265,7 @@ var BankTransactionMobileListItem = ({
7193
7265
  }
7194
7266
  }, []);
7195
7267
  useEffect17(() => {
7196
- if (editable && bankTransaction.recently_categorized) {
7268
+ if (editable && bankTransaction.recently_categorized && shouldHideAfterCategorize(bankTransaction)) {
7197
7269
  setTimeout(() => {
7198
7270
  removeTransaction(bankTransaction);
7199
7271
  }, 300);
@@ -7224,7 +7296,7 @@ var BankTransactionMobileListItem = ({
7224
7296
  },
7225
7297
  isCredit(bankTransaction) ? "+$" : " $",
7226
7298
  centsToDollars(bankTransaction.amount)
7227
- ), /* @__PURE__ */ React92.createElement("span", { className: `${className}__heading__date` }, formatTime8(parseISO10(bankTransaction.date), DATE_FORMAT2))))
7299
+ ), /* @__PURE__ */ React92.createElement("span", { className: `${className}__heading__date` }, formatTime8(parseISO9(bankTransaction.date), DATE_FORMAT2))))
7228
7300
  ), categorizationEnabled(mode) ? /* @__PURE__ */ React92.createElement(
7229
7301
  "div",
7230
7302
  {
@@ -7747,11 +7819,11 @@ var DownloadCloud = ({ size = 18, ...props }) => /* @__PURE__ */ React103.create
7747
7819
  var DownloadCloud_default = DownloadCloud;
7748
7820
 
7749
7821
  // src/utils/business.ts
7750
- import { differenceInCalendarMonths, parseISO as parseISO11, startOfMonth } from "date-fns";
7822
+ import { differenceInCalendarMonths, parseISO as parseISO10, startOfMonth } from "date-fns";
7751
7823
  var getActivationDate = (business) => {
7752
7824
  try {
7753
7825
  if (business && business.activation_at) {
7754
- return parseISO11(business.activation_at);
7826
+ return parseISO10(business.activation_at);
7755
7827
  }
7756
7828
  return;
7757
7829
  } catch (_err) {
@@ -7777,7 +7849,7 @@ var isDateAllowedToBrowse = (date, business) => {
7777
7849
  };
7778
7850
 
7779
7851
  // src/components/DatePicker/DatePicker.tsx
7780
- import React105, { useEffect as useEffect18, useRef as useRef13, useState as useState23 } from "react";
7852
+ import React105, { useEffect as useEffect18, useRef as useRef14, useState as useState23 } from "react";
7781
7853
  import ReactDatePicker from "react-datepicker";
7782
7854
 
7783
7855
  // src/components/DatePicker/DatePickerOptions.tsx
@@ -7940,7 +8012,7 @@ var DatePicker = ({
7940
8012
  navigateArrows = mode === "monthPicker",
7941
8013
  ...props
7942
8014
  }) => {
7943
- const pickerRef = useRef13(null);
8015
+ const pickerRef = useRef14(null);
7944
8016
  const [updatePickerDate, setPickerDate] = useState23(false);
7945
8017
  const [selectedDates, setSelectedDates] = useState23(selected);
7946
8018
  const { isDesktop } = useSizeClass();
@@ -8336,7 +8408,7 @@ var DataStates = ({
8336
8408
  editable
8337
8409
  }) => {
8338
8410
  let title = editable ? "You are up to date with transactions!" : "You have no categorized transactions";
8339
- let description = editable ? "All uncategorized transaction will be displayed here" : "All transaction will be displayed here once reviewed";
8411
+ let description = editable ? "All uncategorized transactions will be displayed here" : "All transactions will be displayed here once reviewed";
8340
8412
  const showRefreshButton = bankTransactions?.length;
8341
8413
  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(
8342
8414
  DataState,
@@ -8361,10 +8433,9 @@ var DataStates = ({
8361
8433
  };
8362
8434
 
8363
8435
  // src/components/BankTransactions/BankTransactions.tsx
8364
- import { endOfMonth as endOfMonth3, parseISO as parseISO12, startOfMonth as startOfMonth4 } from "date-fns";
8436
+ import { endOfMonth as endOfMonth3, parseISO as parseISO11, startOfMonth as startOfMonth4 } from "date-fns";
8365
8437
  var COMPONENT_NAME2 = "bank-transactions";
8366
8438
  var TEST_EMPTY_STATE = false;
8367
- var POLL_INTERVAL = 1e3;
8368
8439
  var categorizationEnabled = (mode) => {
8369
8440
  if (mode === "bookkeeping-client") {
8370
8441
  return false;
@@ -8384,6 +8455,7 @@ var BankTransactionsContent = ({
8384
8455
  showDescriptions = false,
8385
8456
  showReceiptUploads = false,
8386
8457
  monthlyView = false,
8458
+ categorizeView: categorizeViewProp,
8387
8459
  mobileComponent,
8388
8460
  filters: inputFilters,
8389
8461
  hideHeader = false,
@@ -8395,7 +8467,7 @@ var BankTransactionsContent = ({
8395
8467
  startDate: startOfMonth4(/* @__PURE__ */ new Date()),
8396
8468
  endDate: endOfMonth3(/* @__PURE__ */ new Date())
8397
8469
  });
8398
- const categorizeView = categorizationEnabled(mode);
8470
+ const categorizeView = categorizeViewProp ?? categorizationEnabled(mode);
8399
8471
  const {
8400
8472
  activate,
8401
8473
  data,
@@ -8411,51 +8483,23 @@ var BankTransactionsContent = ({
8411
8483
  fetchMore,
8412
8484
  removeAfterCategorize
8413
8485
  } = useBankTransactionsContext();
8414
- const { data: linkedAccounts, refetchAccounts } = useLinkedAccounts();
8486
+ const { data: linkedAccounts } = useLinkedAccounts();
8415
8487
  const isSyncing = useMemo6(
8416
8488
  () => Boolean(linkedAccounts?.some((item) => item.is_syncing)),
8417
8489
  [linkedAccounts]
8418
8490
  );
8419
- const transactionsNotSynced = useMemo6(
8420
- () => loadingStatus === "complete" && isSyncing && (!data || data?.length === 0),
8421
- [data, isSyncing, loadingStatus]
8422
- );
8423
- let intervalId = void 0;
8424
- const [refreshTrigger, setRefreshTrigger] = useState25(-1);
8425
- useEffect19(() => {
8426
- if (refreshTrigger !== -1) {
8427
- refetch();
8428
- refetchAccounts();
8429
- }
8430
- }, [refreshTrigger]);
8431
- useEffect19(() => {
8432
- if (isSyncing) {
8433
- intervalId = setInterval(() => {
8434
- setRefreshTrigger(Math.random());
8435
- }, POLL_INTERVAL);
8436
- } else {
8437
- if (intervalId) {
8438
- clearInterval(intervalId);
8439
- }
8440
- }
8441
- return () => {
8442
- if (intervalId) {
8443
- clearInterval(intervalId);
8444
- }
8445
- };
8446
- }, [isSyncing, transactionsNotSynced]);
8447
8491
  useEffect19(() => {
8448
8492
  activate();
8449
8493
  }, []);
8450
8494
  useEffect19(() => {
8451
8495
  if (JSON.stringify(inputFilters) !== JSON.stringify(filters)) {
8452
- if (!filters?.categorizationStatus && categorizeView) {
8496
+ if (!inputFilters?.categorizationStatus && categorizeView) {
8453
8497
  setFilters({
8454
8498
  ...filters,
8455
8499
  ...inputFilters,
8456
8500
  categorizationStatus: "review" /* review */
8457
8501
  });
8458
- } else if (!filters?.categorizationStatus && !categorizationEnabled(mode)) {
8502
+ } else if (!inputFilters?.categorizationStatus && !categorizationEnabled(mode)) {
8459
8503
  setFilters({
8460
8504
  ...filters,
8461
8505
  ...inputFilters,
@@ -8464,11 +8508,11 @@ var BankTransactionsContent = ({
8464
8508
  } else {
8465
8509
  setFilters({ ...filters, ...inputFilters });
8466
8510
  }
8467
- } else if (!filters?.categorizationStatus && categorizeView) {
8511
+ } else if (!inputFilters?.categorizationStatus && categorizeView) {
8468
8512
  setFilters({
8469
8513
  categorizationStatus: "review" /* review */
8470
8514
  });
8471
- } else if (!filters?.categorizationStatus && !categorizationEnabled(mode)) {
8515
+ } else if (!inputFilters?.categorizationStatus && !categorizationEnabled(mode)) {
8472
8516
  setFilters({
8473
8517
  categorizationStatus: "categorized" /* categorized */
8474
8518
  });
@@ -8485,7 +8529,7 @@ var BankTransactionsContent = ({
8485
8529
  const bankTransactions = TEST_EMPTY_STATE ? [] : useMemo6(() => {
8486
8530
  if (monthlyView) {
8487
8531
  return data?.filter(
8488
- (x) => parseISO12(x.date) >= dateRange.startDate && parseISO12(x.date) <= dateRange.endDate
8532
+ (x) => parseISO11(x.date) >= dateRange.startDate && parseISO11(x.date) <= dateRange.endDate
8489
8533
  );
8490
8534
  }
8491
8535
  const firstPageIndex = (currentPage - 1) * pageSize;
@@ -8494,7 +8538,7 @@ var BankTransactionsContent = ({
8494
8538
  }, [currentPage, data, dateRange]);
8495
8539
  const onCategorizationDisplayChange = (event) => {
8496
8540
  setFilters({
8497
- categorizationStatus: event.target.value === "categorized" /* categorized */ ? "categorized" /* categorized */ : "review" /* review */
8541
+ categorizationStatus: event.target.value === "categorized" /* categorized */ ? "categorized" /* categorized */ : event.target.value === "all" /* all */ ? "all" /* all */ : "review" /* review */
8498
8542
  });
8499
8543
  setCurrentPage(1);
8500
8544
  };
@@ -8520,7 +8564,7 @@ var BankTransactionsContent = ({
8520
8564
  }
8521
8565
  debounceContainerWidth(size?.width);
8522
8566
  });
8523
- const editable = display === "review" /* review */;
8567
+ const editable = display === "review" /* review */ || display === "all" /* all */;
8524
8568
  const isLastPage = data && !hasMore && Math.ceil((data?.length || 0) / pageSize) === currentPage;
8525
8569
  return /* @__PURE__ */ React109.createElement(
8526
8570
  Container,
@@ -8621,7 +8665,7 @@ var BankTransactionsContent = ({
8621
8665
  import React110 from "react";
8622
8666
 
8623
8667
  // src/hooks/useQuickbooks/useQuickbooks.ts
8624
- import { useEffect as useEffect20, useRef as useRef14, useState as useState26 } from "react";
8668
+ import { useEffect as useEffect20, useRef as useRef16, useState as useState26 } from "react";
8625
8669
  var DEBUG2 = true;
8626
8670
  var useQuickbooks = () => {
8627
8671
  const { auth, businessId, apiUrl } = useLayerContext();
@@ -8629,7 +8673,7 @@ var useQuickbooks = () => {
8629
8673
  const [quickbooksIsLinked, setQuickbooksIsLinked] = useState26(
8630
8674
  null
8631
8675
  );
8632
- const syncStatusIntervalRef = useRef14(null);
8676
+ const syncStatusIntervalRef = useRef16(null);
8633
8677
  useEffect20(() => {
8634
8678
  if (isSyncingFromQuickbooks && syncStatusIntervalRef.current === null) {
8635
8679
  const interval = setInterval(() => fetchIsSyncingFromQuickbooks(), 2e3);
@@ -11080,7 +11124,7 @@ var TableRow = ({
11080
11124
  };
11081
11125
 
11082
11126
  // src/components/Table/Table.tsx
11083
- import React128, { useEffect as useEffect26, useRef as useRef15 } from "react";
11127
+ import React128, { useEffect as useEffect26, useRef as useRef17 } from "react";
11084
11128
  import classNames47 from "classnames";
11085
11129
  var Table = ({
11086
11130
  componentName,
@@ -11088,8 +11132,8 @@ var Table = ({
11088
11132
  borderCollapse = "separate",
11089
11133
  bottomSpacing = true
11090
11134
  }) => {
11091
- const tableRef = useRef15(null);
11092
- const prevChildrenRef = useRef15([]);
11135
+ const tableRef = useRef17(null);
11136
+ const prevChildrenRef = useRef17([]);
11093
11137
  useEffect26(() => {
11094
11138
  if (tableRef.current) {
11095
11139
  const tbody = tableRef.current.querySelector("tbody");
@@ -13077,7 +13121,7 @@ var Card = ({ children, className }) => {
13077
13121
 
13078
13122
  // src/components/DateTime/DateTime.tsx
13079
13123
  import React149 from "react";
13080
- import { parseISO as parseISO13, format as formatTime9 } from "date-fns";
13124
+ import { parseISO as parseISO12, format as formatTime9 } from "date-fns";
13081
13125
  var DateTime = ({
13082
13126
  value,
13083
13127
  format: format7,
@@ -13087,10 +13131,10 @@ var DateTime = ({
13087
13131
  onlyTime
13088
13132
  }) => {
13089
13133
  if (format7) {
13090
- return /* @__PURE__ */ React149.createElement(Text, { className: "Layer__datetime" }, formatTime9(parseISO13(value), format7));
13134
+ return /* @__PURE__ */ React149.createElement(Text, { className: "Layer__datetime" }, formatTime9(parseISO12(value), format7));
13091
13135
  }
13092
- const date = formatTime9(parseISO13(value), dateFormat ?? DATE_FORMAT);
13093
- const time = formatTime9(parseISO13(value), timeFormat ?? TIME_FORMAT);
13136
+ const date = formatTime9(parseISO12(value), dateFormat ?? DATE_FORMAT);
13137
+ const time = formatTime9(parseISO12(value), timeFormat ?? TIME_FORMAT);
13094
13138
  return /* @__PURE__ */ React149.createElement(Text, { className: "Layer__datetime" }, !onlyTime && /* @__PURE__ */ React149.createElement(
13095
13139
  Text,
13096
13140
  {
@@ -13255,7 +13299,7 @@ var LedgerAccountEntryDetails = ({ stringOverrides }) => {
13255
13299
  // src/components/LedgerAccount/LedgerAccountRow.tsx
13256
13300
  import React153, { useContext as useContext23, useEffect as useEffect36, useState as useState40 } from "react";
13257
13301
  import classNames54 from "classnames";
13258
- import { parseISO as parseISO14, format as formatTime10 } from "date-fns";
13302
+ import { parseISO as parseISO13, format as formatTime10 } from "date-fns";
13259
13303
  var LedgerAccountRow = ({
13260
13304
  row,
13261
13305
  index,
@@ -13294,7 +13338,7 @@ var LedgerAccountRow = ({
13294
13338
  }
13295
13339
  }
13296
13340
  },
13297
- /* @__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(
13341
+ /* @__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(
13298
13342
  Text,
13299
13343
  {
13300
13344
  weight: "normal" /* normal */,
@@ -13327,7 +13371,7 @@ var LedgerAccountRow = ({
13327
13371
  }
13328
13372
  }
13329
13373
  },
13330
- /* @__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(
13374
+ /* @__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(
13331
13375
  Text,
13332
13376
  {
13333
13377
  weight: "normal" /* normal */,
@@ -13356,7 +13400,7 @@ var LedgerAccountRow = ({
13356
13400
  }
13357
13401
  }
13358
13402
  },
13359
- /* @__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))),
13403
+ /* @__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))),
13360
13404
  /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, row.entry_id.substring(0, 5))),
13361
13405
  /* @__PURE__ */ React153.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React153.createElement("span", { className: "Layer__table-cell-content" }, row.source?.display_description ?? "")),
13362
13406
  /* @__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)}`)),
@@ -13866,7 +13910,7 @@ import React161, { useContext as useContext31, useMemo as useMemo17, useState as
13866
13910
  // src/components/JournalRow/JournalRow.tsx
13867
13911
  import React156, { useContext as useContext26, useEffect as useEffect39, useState as useState44 } from "react";
13868
13912
  import classNames56 from "classnames";
13869
- import { parseISO as parseISO15, format as formatTime11 } from "date-fns";
13913
+ import { parseISO as parseISO14, format as formatTime11 } from "date-fns";
13870
13914
  var INDENTATION2 = 24;
13871
13915
  var EXPANDED_STYLE3 = {
13872
13916
  height: "100%",
@@ -13979,7 +14023,7 @@ var JournalRow = ({
13979
14023
  )
13980
14024
  ))),
13981
14025
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, row.id.substring(0, 5))),
13982
- /* @__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))),
14026
+ /* @__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))),
13983
14027
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, humanizeEnum(row.entry_type))),
13984
14028
  /* @__PURE__ */ React156.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React156.createElement("span", { className: "Layer__table-cell-content" }, `(${row.line_items.length})`)),
13985
14029
  /* @__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(
@@ -15457,7 +15501,7 @@ var GeneralLedgerView = ({
15457
15501
  };
15458
15502
 
15459
15503
  // src/views/Reports/Reports.tsx
15460
- import React180, { useContext as useContext38, useRef as useRef16, useState as useState55 } from "react";
15504
+ import React180, { useContext as useContext38, useRef as useRef18, useState as useState55 } from "react";
15461
15505
  var DownloadButton2 = ({
15462
15506
  stringOverrides
15463
15507
  }) => {
@@ -15529,7 +15573,7 @@ var Reports = ({
15529
15573
  stringOverrides,
15530
15574
  enabledReports = ["profitAndLoss", "balanceSheet", "statementOfCashFlow"]
15531
15575
  }) => {
15532
- const containerRef = useRef16(null);
15576
+ const containerRef = useRef18(null);
15533
15577
  const [activeTab, setActiveTab] = useState55(enabledReports[0]);
15534
15578
  const options = getOptions(enabledReports);
15535
15579
  const defaultTitle = enabledReports.length > 1 ? "Reports" : options.find((option) => option.value = enabledReports[0])?.label;
@@ -15597,10 +15641,10 @@ var ReportsPanel = ({
15597
15641
  };
15598
15642
 
15599
15643
  // src/components/ProfitAndLossView/ProfitAndLossView.tsx
15600
- import React181, { useContext as useContext39, useRef as useRef17 } from "react";
15644
+ import React181, { useContext as useContext39, useRef as useRef19 } from "react";
15601
15645
  var COMPONENT_NAME7 = "profit-and-loss";
15602
15646
  var ProfitAndLossView = (props) => {
15603
- const containerRef = useRef17(null);
15647
+ const containerRef = useRef19(null);
15604
15648
  return /* @__PURE__ */ React181.createElement(Container, { name: COMPONENT_NAME7, ref: containerRef }, /* @__PURE__ */ React181.createElement(ProfitAndLoss, null, /* @__PURE__ */ React181.createElement(ProfitAndLossPanel, { containerRef, ...props })));
15605
15649
  };
15606
15650
  var ProfitAndLossPanel = ({
@@ -15681,6 +15725,7 @@ export {
15681
15725
  BookkeepingOverview,
15682
15726
  BookkeepingUpsellBar,
15683
15727
  ChartOfAccounts,
15728
+ Direction,
15684
15729
  DisplayState,
15685
15730
  GeneralLedgerView,
15686
15731
  Journal,
@@ -15694,6 +15739,7 @@ export {
15694
15739
  StatementOfCashFlow,
15695
15740
  Tasks,
15696
15741
  useBankTransactionsContext,
15742
+ useDataSync,
15697
15743
  useLayerContext
15698
15744
  };
15699
15745
  //# sourceMappingURL=index.js.map