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