@layerfi/components 0.1.10 → 0.1.12

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
@@ -202,6 +202,7 @@ var request = (verb) => (url) => (baseUrl, accessToken, options) => fetch(`${bas
202
202
  }).then((res) => handleResponse(res)).catch((error) => handleException(error));
203
203
  var post = request("post");
204
204
  var put = request("put");
205
+ var deleteRequest = request("delete");
205
206
  var handleResponse = async (res) => {
206
207
  if (!res.ok) {
207
208
  const errors = await tryToReadErrorsFromResponse(res);
@@ -261,21 +262,38 @@ var matchBankTransaction = put(
261
262
  // src/api/layer/categories.ts
262
263
  var getCategories = get(({ businessId }) => `/v1/businesses/${businessId}/categories`);
263
264
 
264
- // src/api/layer/linked_accounts.ts
265
- var getLinkedAccounts = get(
266
- ({ businessId }) => `/v1/businesses/${businessId}/external-accounts`
267
- );
268
-
269
- // src/api/layer/ledger_accounts.ts
270
- var getLedgerAccounts = get(
265
+ // src/api/layer/chart_of_accounts.ts
266
+ var getChartOfAccounts = get(
271
267
  ({ businessId }) => `/v1/businesses/${businessId}/ledger/accounts`
272
268
  );
269
+ var getLedgerAccountBalances = get(
270
+ ({ businessId }) => `/v1/businesses/${businessId}/ledger/balances`
271
+ );
273
272
  var createAccount = post(
274
273
  ({ businessId }) => `/v1/businesses/${businessId}/ledger/accounts`
275
274
  );
276
275
  var updateAccount = put(
277
276
  ({ businessId, accountId }) => `/v1/businesses/${businessId}/ledger/accounts/${accountId}`
278
277
  );
278
+ var getLedgerAccountsLines = get(
279
+ ({ businessId, accountId }) => `/v1/businesses/${businessId}/ledger/accounts/${accountId}/lines`
280
+ );
281
+ var getLedgerAccountsEntry = get(
282
+ ({ businessId, entryId }) => `/v1/businesses/${businessId}/ledger/entries/${entryId}`
283
+ );
284
+
285
+ // src/api/layer/linked_accounts.ts
286
+ var getLinkedAccounts = get(
287
+ ({ businessId }) => `/v1/businesses/${businessId}/external-accounts`
288
+ );
289
+ var getPlaidLinkToken = post(({ businessId }) => `/v1/businesses/${businessId}/plaid/link`);
290
+ var exchangePlaidPublicToken = post(({ businessId }) => `/v1/businesses/${businessId}/plaid/link/exchange`);
291
+ var unlinkPlaidItem = deleteRequest(
292
+ ({ businessId, plaidItemId }) => `/v1/businesses/${businessId}/plaid/items/${plaidItemId}`
293
+ );
294
+ var unlinkPlaidAccount = post(
295
+ ({ businessId, accountId }) => `/v1/businesses/${businessId}/plaid/accounts/${accountId}/archive`
296
+ );
279
297
 
280
298
  // src/api/layer/profit_and_loss.ts
281
299
  var getProfitAndLoss = get(
@@ -292,9 +310,16 @@ var Layer = {
292
310
  getBalanceSheet,
293
311
  getBankTransactions,
294
312
  getCategories,
295
- getLedgerAccounts,
313
+ getChartOfAccounts,
314
+ getLedgerAccountBalances,
315
+ getLedgerAccountsLines,
316
+ getLedgerAccountsEntry,
296
317
  getProfitAndLoss,
297
- getLinkedAccounts
318
+ getLinkedAccounts,
319
+ getPlaidLinkToken,
320
+ exchangePlaidPublicToken,
321
+ unlinkPlaidAccount,
322
+ unlinkPlaidItem
298
323
  };
299
324
 
300
325
  // src/hooks/useLayerContext/useLayerContext.tsx
@@ -315,7 +340,10 @@ var LayerContext = createContext({
315
340
  theme: void 0,
316
341
  colors: {},
317
342
  setTheme: () => void 0,
318
- getColor: (_shade) => void 0
343
+ getColor: (_shade) => void 0,
344
+ setLightColor: () => void 0,
345
+ setDarkColor: () => void 0,
346
+ setColors: () => void 0
319
347
  });
320
348
 
321
349
  // src/hooks/useLayerContext/useLayerContext.tsx
@@ -595,6 +623,11 @@ import React56, { useState as useState10, useMemo as useMemo2, useEffect as useE
595
623
 
596
624
  // src/config/general.ts
597
625
  var DATE_FORMAT = "LLL d, yyyy";
626
+ var TIME_FORMAT = "p";
627
+ var BREAKPOINTS = {
628
+ TABLET: 760,
629
+ MOBILE: 500
630
+ };
598
631
 
599
632
  // src/hooks/useBankTransactions/useBankTransactions.tsx
600
633
  import useSWR2 from "swr";
@@ -715,7 +748,9 @@ var useElementSize = (callback) => {
715
748
  const observer = new ResizeObserver((entries) => {
716
749
  callback(element, entries[0], {
717
750
  width: element.offsetWidth,
718
- height: element.offsetHeight
751
+ height: element.offsetHeight,
752
+ clientWidth: element.clientWidth,
753
+ clientHeight: element.clientHeight
719
754
  });
720
755
  });
721
756
  observer.observe(element);
@@ -1532,13 +1567,17 @@ var Badge = ({
1532
1567
  onClick,
1533
1568
  children,
1534
1569
  tooltip,
1535
- size = "medium" /* MEDIUM */
1570
+ size = "medium" /* MEDIUM */,
1571
+ variant = "default" /* DEFAULT */,
1572
+ hoverable = false
1536
1573
  }) => {
1537
1574
  const baseProps = {
1538
1575
  className: classNames7(
1539
1576
  "Layer__badge",
1577
+ hoverable && !tooltip ? "Layer__badge--with-hover" : "",
1540
1578
  onClick || tooltip ? "Layer__badge--clickable" : "",
1541
- `Layer__badge--${size}`
1579
+ `Layer__badge--${size}`,
1580
+ `Layer__badge--${variant}`
1542
1581
  ),
1543
1582
  onClick,
1544
1583
  children
@@ -2181,7 +2220,8 @@ var Select2 = ({
2181
2220
  classNamePrefix = "Layer__select",
2182
2221
  value,
2183
2222
  onChange,
2184
- disabled
2223
+ disabled,
2224
+ placeholder
2185
2225
  }) => {
2186
2226
  return /* @__PURE__ */ React37.createElement(
2187
2227
  ReactSelect,
@@ -2189,6 +2229,7 @@ var Select2 = ({
2189
2229
  name,
2190
2230
  className: `Layer__select ${className ?? ""}`,
2191
2231
  classNamePrefix,
2232
+ placeholder: placeholder ?? "Select...",
2192
2233
  options,
2193
2234
  value,
2194
2235
  onChange: (newValue) => newValue && onChange(newValue),
@@ -2394,6 +2435,7 @@ var Toggle = ({
2394
2435
  checked: selectedValue === option.value,
2395
2436
  onChange: handleChange,
2396
2437
  disabled: option.disabled ?? false,
2438
+ disabledMessage: option.disabledMessage,
2397
2439
  index
2398
2440
  }
2399
2441
  )), /* @__PURE__ */ React41.createElement("span", { className: "Layer__toggle__thumb", style: { ...thumbPos } }));
@@ -2407,6 +2449,7 @@ var ToggleOption = ({
2407
2449
  size,
2408
2450
  leftIcon,
2409
2451
  disabled,
2452
+ disabledMessage = "Disabled",
2410
2453
  index
2411
2454
  }) => {
2412
2455
  if (disabled) {
@@ -2421,7 +2464,7 @@ var ToggleOption = ({
2421
2464
  disabled: disabled ?? false,
2422
2465
  "data-idx": index
2423
2466
  }
2424
- ), /* @__PURE__ */ React41.createElement("span", { className: "Layer__toggle-option-content" }, leftIcon && /* @__PURE__ */ React41.createElement("span", { className: "Layer__toggle-option__icon" }, leftIcon), /* @__PURE__ */ React41.createElement("span", null, label)))), /* @__PURE__ */ React41.createElement(TooltipContent, { className: "Layer__tooltip" }, "We could not find matching transactions"));
2467
+ ), /* @__PURE__ */ React41.createElement("span", { className: "Layer__toggle-option-content" }, leftIcon && /* @__PURE__ */ React41.createElement("span", { className: "Layer__toggle-option__icon" }, leftIcon), /* @__PURE__ */ React41.createElement("span", null, label)))), /* @__PURE__ */ React41.createElement(TooltipContent, { className: "Layer__tooltip" }, disabledMessage));
2425
2468
  }
2426
2469
  return /* @__PURE__ */ React41.createElement("label", { className: `Layer__toggle-option`, "data-checked": checked }, /* @__PURE__ */ React41.createElement(
2427
2470
  "input",
@@ -2822,7 +2865,8 @@ var ExpandedBankTransactionRow = forwardRef2(
2822
2865
  {
2823
2866
  value: "match",
2824
2867
  label: "Match",
2825
- disabled: !hasMatch(bankTransaction)
2868
+ disabled: !hasMatch(bankTransaction),
2869
+ disabledMessage: "We could not find matching transactions"
2826
2870
  }
2827
2871
  ],
2828
2872
  selected: purpose,
@@ -3008,7 +3052,15 @@ var extractDescriptionForSplit = (category) => {
3008
3052
  return category.entries.map((c) => c.category.display_name).join(", ");
3009
3053
  };
3010
3054
  var getDefaultSelectedCategory = (bankTransaction) => {
3011
- return hasSuggestions(bankTransaction.categorization_flow) ? mapCategoryToOption(bankTransaction.categorization_flow.suggestions[0]) : bankTransaction.suggested_matches?.length === 1 ? mapSuggestedMatchToOption(bankTransaction.suggested_matches[0]) : void 0;
3055
+ if (bankTransaction.suggested_matches?.[0]) {
3056
+ return mapSuggestedMatchToOption(bankTransaction.suggested_matches?.[0]);
3057
+ }
3058
+ if (hasSuggestions(bankTransaction.categorization_flow)) {
3059
+ return mapCategoryToOption(
3060
+ bankTransaction.categorization_flow.suggestions[0]
3061
+ );
3062
+ }
3063
+ return void 0;
3012
3064
  };
3013
3065
  var clickTimer = Date.now();
3014
3066
  var BankTransactionRow = ({
@@ -3686,11 +3738,12 @@ var hslToHex = (hsl) => {
3686
3738
  // src/components/Container/Container.tsx
3687
3739
  import classNames20 from "classnames";
3688
3740
  var Container = forwardRef3(
3689
- ({ name, className, children, asWidget }, ref) => {
3741
+ ({ name, className, children, asWidget, elevated = false }, ref) => {
3690
3742
  const baseClassName = classNames20(
3691
3743
  "Layer__component Layer__component-container",
3692
3744
  `Layer__${name}`,
3693
- asWidget ? "Layer__component--as-widget" : "",
3745
+ elevated && "Layer__component--elevated",
3746
+ asWidget && "Layer__component--as-widget",
3694
3747
  className
3695
3748
  );
3696
3749
  const { theme } = useLayerContext();
@@ -4022,7 +4075,14 @@ var BankTransactions = ({
4022
4075
  className: "Layer__bank-transactions__header",
4023
4076
  style: { top: shiftStickyHeader }
4024
4077
  },
4025
- /* @__PURE__ */ React56.createElement(Heading, { className: "Layer__bank-transactions__title" }, "Transactions"),
4078
+ /* @__PURE__ */ React56.createElement(
4079
+ Heading,
4080
+ {
4081
+ className: "Layer__bank-transactions__title",
4082
+ size: asWidget ? "secondary" /* secondary */ : "secondary" /* secondary */
4083
+ },
4084
+ "Transactions"
4085
+ ),
4026
4086
  !categorizedOnly && /* @__PURE__ */ React56.createElement(
4027
4087
  Toggle,
4028
4088
  {
@@ -4123,12 +4183,17 @@ var Hello = ({ user }) => {
4123
4183
  import React64 from "react";
4124
4184
 
4125
4185
  // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
4126
- import useSWR4 from "swr";
4127
- var MOCK_DATA = [
4186
+ import { useEffect as useEffect8, useState as useState11 } from "react";
4187
+ import { usePlaidLink } from "react-plaid-link";
4188
+
4189
+ // src/hooks/useLinkedAccounts/mockData.ts
4190
+ var LINKED_ACCOUNTS_MOCK_DATA = [
4128
4191
  {
4129
4192
  id: "1",
4193
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4194
+ external_account_source: "PLAID",
4130
4195
  external_account_name: "Citi Double Cash\xAE Card",
4131
- external_account_number: "1234",
4196
+ //external_account_number: '1234',
4132
4197
  latest_balance_timestamp: {
4133
4198
  external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4134
4199
  external_account_source: "PLAID",
@@ -4137,13 +4202,19 @@ var MOCK_DATA = [
4137
4202
  created_at: "2024-04-06T16:44:35.715458Z"
4138
4203
  },
4139
4204
  current_ledger_balance: 373717,
4140
- institution: "Chase",
4141
- institutionLogo: ""
4205
+ institution: {
4206
+ name: "Chase",
4207
+ logo: ""
4208
+ }
4209
+ //connection_id: '0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq',
4210
+ //connection_status: 'OK',
4142
4211
  },
4143
4212
  {
4144
4213
  id: "2",
4214
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4215
+ external_account_source: "PLAID",
4145
4216
  external_account_name: "Citi Double Cash\xAE Card",
4146
- external_account_number: "1234",
4217
+ //external_account_number: '1234',
4147
4218
  latest_balance_timestamp: {
4148
4219
  external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4149
4220
  external_account_source: "PLAID",
@@ -4152,13 +4223,19 @@ var MOCK_DATA = [
4152
4223
  created_at: "2024-04-06T16:44:35.715458Z"
4153
4224
  },
4154
4225
  current_ledger_balance: 373717,
4155
- institution: "Chase",
4156
- institutionLogo: ""
4226
+ institution: {
4227
+ name: "Chase",
4228
+ logo: ""
4229
+ }
4230
+ //connection_id: '0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq',
4231
+ //connection_status: 'OK',
4157
4232
  },
4158
4233
  {
4159
4234
  id: "3",
4235
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4236
+ external_account_source: "PLAID",
4160
4237
  external_account_name: "Citi Double Cash\xAE Card",
4161
- external_account_number: "1234",
4238
+ //external_account_number: '1234',
4162
4239
  latest_balance_timestamp: {
4163
4240
  external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4164
4241
  external_account_source: "PLAID",
@@ -4167,13 +4244,19 @@ var MOCK_DATA = [
4167
4244
  created_at: "2024-04-06T16:44:35.715458Z"
4168
4245
  },
4169
4246
  current_ledger_balance: 373717,
4170
- institution: "Chase",
4171
- institutionLogo: ""
4247
+ institution: {
4248
+ name: "Chase",
4249
+ logo: ""
4250
+ }
4251
+ //connection_id: '0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq',
4252
+ //connection_status: 'OK',
4172
4253
  },
4173
4254
  {
4174
4255
  id: "4",
4256
+ external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4257
+ external_account_source: "PLAID",
4175
4258
  external_account_name: "Citi Double Cash\xAE Card",
4176
- external_account_number: "1234",
4259
+ //external_account_number: '1234',
4177
4260
  latest_balance_timestamp: {
4178
4261
  external_account_external_id: "0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq",
4179
4262
  external_account_source: "PLAID",
@@ -4182,14 +4265,25 @@ var MOCK_DATA = [
4182
4265
  created_at: "2024-04-06T16:44:35.715458Z"
4183
4266
  },
4184
4267
  current_ledger_balance: 373717,
4185
- institution: "Chase",
4186
- institutionLogo: ""
4268
+ institution: {
4269
+ name: "Chase",
4270
+ logo: ""
4271
+ }
4272
+ //connection_id: '0Br385JmgbTryJn8nEBnUb4A5ydv06U9Vbqqq',
4273
+ //connection_status: 'OK',
4187
4274
  }
4188
4275
  ];
4276
+
4277
+ // src/hooks/useLinkedAccounts/useLinkedAccounts.ts
4278
+ import useSWR4 from "swr";
4279
+ var DEBUG = true;
4280
+ var USE_MOCK_RESPONSE_DATA = false;
4281
+ var USE_PLAID_SANDBOX = true;
4189
4282
  var useLinkedAccounts = () => {
4190
4283
  const { auth, businessId, apiUrl } = useLayerContext();
4284
+ const [linkToken, setLinkToken] = useState11(null);
4191
4285
  const {
4192
- // data: responseData,
4286
+ data: responseData,
4193
4287
  isLoading,
4194
4288
  isValidating,
4195
4289
  error: responseError,
@@ -4200,27 +4294,80 @@ var useLinkedAccounts = () => {
4200
4294
  params: { businessId }
4201
4295
  })
4202
4296
  );
4203
- const responseData = { data: MOCK_DATA, meta: {}, error: void 0 };
4204
- const addAccount = () => {
4205
- console.log("add account...");
4297
+ useEffect8(() => {
4298
+ const getLinkToken = async () => {
4299
+ if (auth?.access_token) {
4300
+ const linkToken2 = (await Layer.getPlaidLinkToken(apiUrl, auth.access_token, {
4301
+ params: { businessId }
4302
+ })).data.link_token;
4303
+ setLinkToken(linkToken2);
4304
+ }
4305
+ };
4306
+ getLinkToken();
4307
+ }, [setLinkToken, auth?.access_token]);
4308
+ const exchangePublicToken = async (publicToken, metadata) => {
4309
+ await Layer.exchangePlaidPublicToken(apiUrl, auth?.access_token, {
4310
+ params: { businessId },
4311
+ body: { public_token: publicToken, institution_id: metadata.institution }
4312
+ });
4313
+ refetchAccounts();
4314
+ };
4315
+ const { open: plaidLinkStart, ready: plaidLinkReady } = usePlaidLink({
4316
+ token: linkToken,
4317
+ onSuccess: exchangePublicToken,
4318
+ env: USE_PLAID_SANDBOX ? "sandbox" : void 0
4319
+ });
4320
+ const mockResponseData = {
4321
+ data: LINKED_ACCOUNTS_MOCK_DATA,
4322
+ meta: {},
4323
+ error: void 0
4324
+ };
4325
+ const addConnection = (source) => {
4326
+ if (source === "PLAID") {
4327
+ linkPlaidItem();
4328
+ } else {
4329
+ console.error(`Connection with source ${source} not yet supported`);
4330
+ }
4331
+ };
4332
+ const removeConnection = (source, connectionId) => {
4333
+ if (source === "PLAID") {
4334
+ unlinkPlaidItem2(connectionId);
4335
+ } else {
4336
+ console.error(`Connection with source ${source} not yet supported`);
4337
+ }
4338
+ };
4339
+ const linkPlaidItem = async () => {
4340
+ DEBUG && console.log("add account...");
4341
+ console.log("plaidLinkReady", plaidLinkReady);
4342
+ plaidLinkReady && plaidLinkStart();
4343
+ };
4344
+ const unlinkPlaidItem2 = (plaidItemId) => {
4345
+ DEBUG && console.log("unlinking plaid item");
4346
+ Layer.unlinkPlaidItem(apiUrl, auth?.access_token, {
4347
+ params: { businessId, plaidItemId }
4348
+ });
4206
4349
  };
4207
- const unlinkAccount = () => {
4208
- console.log("unlink account...");
4350
+ const unlinkAccount = (plaidAccountId) => {
4351
+ DEBUG && console.log("unlinking account");
4352
+ Layer.unlinkPlaidAccount(apiUrl, auth?.access_token, {
4353
+ params: { businessId, accountId: plaidAccountId }
4354
+ });
4209
4355
  };
4210
4356
  const renewLinkAccount = () => {
4211
- console.log("relink account...");
4357
+ DEBUG && console.log("relink account...");
4212
4358
  };
4213
- const refetch = () => {
4214
- console.log("refetch...");
4359
+ const refetchAccounts = () => {
4360
+ DEBUG && console.log("refetching plaid accounts...");
4361
+ mutate();
4215
4362
  };
4216
4363
  return {
4217
- // data: responseData?.data.external_accounts,
4218
- data: responseData.data,
4364
+ data: USE_MOCK_RESPONSE_DATA ? mockResponseData.data : responseData?.data.external_accounts,
4219
4365
  isLoading,
4220
4366
  isValidating,
4221
4367
  error: responseError,
4222
- refetch,
4223
- addAccount,
4368
+ addConnection,
4369
+ removeConnection,
4370
+ refetchAccounts,
4224
4371
  unlinkAccount,
4225
4372
  renewLinkAccount
4226
4373
  };
@@ -4319,16 +4466,21 @@ var MoreVertical = ({ size = 18, ...props }) => {
4319
4466
  var MoreVertical_default = MoreVertical;
4320
4467
 
4321
4468
  // src/components/HoverMenu/HoverMenu.tsx
4322
- import React60, { useEffect as useEffect8, useRef as useRef12, useState as useState11 } from "react";
4469
+ import React60, { useEffect as useEffect9, useRef as useRef12, useState as useState12 } from "react";
4323
4470
  import classNames22 from "classnames";
4324
- var HoverMenu = ({ children, config }) => {
4325
- const [openMenu, setOpenMenu] = useState11(false);
4471
+ var HoverMenu = ({
4472
+ children,
4473
+ config,
4474
+ plaidItemId,
4475
+ accountId
4476
+ }) => {
4477
+ const [openMenu, setOpenMenu] = useState12(false);
4326
4478
  const hoverMenuRef = useRef12(null);
4327
4479
  const hoverMenuClassName = classNames22(
4328
4480
  "Layer__hover-menu",
4329
- openMenu && "--open"
4481
+ openMenu && "Layer__hover-menu--open"
4330
4482
  );
4331
- useEffect8(() => {
4483
+ useEffect9(() => {
4332
4484
  function handleClickOutside(event) {
4333
4485
  if (hoverMenuRef.current && !hoverMenuRef.current.contains(event.target)) {
4334
4486
  setOpenMenu(false);
@@ -4366,7 +4518,7 @@ var HoverMenu = ({ children, config }) => {
4366
4518
  "button",
4367
4519
  {
4368
4520
  className: "Layer__hover-menu__list-item-button",
4369
- onClick: () => item.action()
4521
+ onClick: () => item.action(plaidItemId, accountId)
4370
4522
  },
4371
4523
  item.name
4372
4524
  )
@@ -4377,9 +4529,19 @@ var HoverMenu = ({ children, config }) => {
4377
4529
  // src/components/LinkedAccountOptions/LinkedAccountOptions.tsx
4378
4530
  var LinkedAccountOptions = ({
4379
4531
  children,
4380
- config
4532
+ config,
4533
+ accountId,
4534
+ plaidItemId
4381
4535
  }) => {
4382
- return /* @__PURE__ */ React61.createElement("div", { className: "Layer__linked-accounts__options" }, /* @__PURE__ */ React61.createElement("div", { className: "Layer__linked-accounts__options-overlay" }, /* @__PURE__ */ React61.createElement("div", { className: "Layer__linked-accounts__options-overlay-button" }, /* @__PURE__ */ React61.createElement(HoverMenu, { config }, /* @__PURE__ */ React61.createElement(MoreVertical_default, { size: 16 })))), children);
4536
+ return /* @__PURE__ */ React61.createElement("div", { className: "Layer__linked-accounts__options" }, /* @__PURE__ */ React61.createElement("div", { className: "Layer__linked-accounts__options-overlay" }, /* @__PURE__ */ React61.createElement("div", { className: "Layer__linked-accounts__options-overlay-button" }, /* @__PURE__ */ React61.createElement(
4537
+ HoverMenu,
4538
+ {
4539
+ config,
4540
+ accountId,
4541
+ plaidItemId
4542
+ },
4543
+ /* @__PURE__ */ React61.createElement(MoreVertical_default, { size: 16 })
4544
+ ))), children);
4383
4545
  };
4384
4546
 
4385
4547
  // src/components/LinkedAccountThumb/LinkedAccountThumb.tsx
@@ -4678,7 +4840,7 @@ var InstitutionIcon_default = InstitutionIcon;
4678
4840
 
4679
4841
  // src/components/LinkedAccountThumb/LinkedAccountThumb.tsx
4680
4842
  import classNames23 from "classnames";
4681
- var AccountNumber = ({ accountNumber }) => /* @__PURE__ */ React63.createElement("div", { className: "account-number" }, /* @__PURE__ */ React63.createElement(Text, { size: "sm" }, "\u2022\u2022\u2022", accountNumber));
4843
+ var AccountNumber = ({ accountNumber }) => /* @__PURE__ */ React63.createElement("div", { className: "account-number" }, /* @__PURE__ */ React63.createElement(Text, { size: "sm" }, "\u2022\u2022\u2022 ", accountNumber));
4682
4844
  var LinkedAccountThumb = ({
4683
4845
  account,
4684
4846
  asWidget
@@ -4687,15 +4849,23 @@ var LinkedAccountThumb = ({
4687
4849
  "Layer__linked-account-thumb",
4688
4850
  asWidget && "--as-widget"
4689
4851
  );
4690
- return /* @__PURE__ */ React63.createElement("div", { className: linkedAccountThumbClassName }, /* @__PURE__ */ React63.createElement("div", { className: "topbar" }, /* @__PURE__ */ React63.createElement("div", { className: "topbar-details" }, /* @__PURE__ */ React63.createElement(Text, { as: "span", className: "account-name" }, account.external_account_name), !asWidget && /* @__PURE__ */ React63.createElement(AccountNumber, { accountNumber: account.external_account_number }), /* @__PURE__ */ React63.createElement(
4852
+ return /* @__PURE__ */ React63.createElement("div", { className: linkedAccountThumbClassName }, /* @__PURE__ */ React63.createElement("div", { className: "topbar" }, /* @__PURE__ */ React63.createElement("div", { className: "topbar-details" }, /* @__PURE__ */ React63.createElement(Text, { as: "span", className: "account-name" }, account.external_account_name), !asWidget && account.mask && /* @__PURE__ */ React63.createElement(AccountNumber, { accountNumber: account.mask }), /* @__PURE__ */ React63.createElement(
4691
4853
  Text,
4692
4854
  {
4693
4855
  as: "span",
4694
4856
  className: "account-institution",
4695
4857
  size: "sm"
4696
4858
  },
4697
- account.institution
4698
- )), /* @__PURE__ */ React63.createElement("div", { className: "topbar-logo" }, !account.institutionLogo && /* @__PURE__ */ React63.createElement(InstitutionIcon_default, null))), !asWidget && /* @__PURE__ */ React63.createElement("div", { className: "middlebar" }, /* @__PURE__ */ React63.createElement(
4859
+ account.institution?.name
4860
+ )), /* @__PURE__ */ React63.createElement("div", { className: "topbar-logo" }, account.logo_base64 != void 0 ? /* @__PURE__ */ React63.createElement(
4861
+ "img",
4862
+ {
4863
+ width: 28,
4864
+ height: 28,
4865
+ src: `data:image/png;base64,${account.logo_base64}`,
4866
+ alt: account.institution?.name
4867
+ }
4868
+ ) : /* @__PURE__ */ React63.createElement(InstitutionIcon_default, null))), !asWidget && /* @__PURE__ */ React63.createElement("div", { className: "middlebar" }, /* @__PURE__ */ React63.createElement(
4699
4869
  Text,
4700
4870
  {
4701
4871
  as: "span",
@@ -4703,28 +4873,33 @@ var LinkedAccountThumb = ({
4703
4873
  size: "sm"
4704
4874
  },
4705
4875
  "Bank balance"
4706
- ), /* @__PURE__ */ React63.createElement(Text, { as: "span", className: "account-balance" }, "$", centsToDollars(account.latest_balance_timestamp.balance))), /* @__PURE__ */ React63.createElement("div", { className: "bottombar" }, asWidget ? /* @__PURE__ */ React63.createElement(AccountNumber, { accountNumber: account.external_account_number }) : /* @__PURE__ */ React63.createElement(
4876
+ ), /* @__PURE__ */ React63.createElement(Text, { as: "span", className: "account-balance" }, "$", centsToDollars(account.latest_balance_timestamp.balance))), /* @__PURE__ */ React63.createElement("div", { className: "bottombar" }, asWidget ? /* @__PURE__ */ React63.createElement(
4877
+ AccountNumber,
4878
+ {
4879
+ accountNumber: "TODO"
4880
+ }
4881
+ ) : /* @__PURE__ */ React63.createElement(
4707
4882
  Text,
4708
4883
  {
4709
4884
  as: "span",
4710
4885
  className: "account-balance-text",
4711
4886
  size: "sm"
4712
4887
  },
4713
- "General ledger balance"
4888
+ "Ledger balance"
4714
4889
  ), /* @__PURE__ */ React63.createElement(Text, { as: "span", className: "account-balance" }, "$", centsToDollars(account.current_ledger_balance))));
4715
4890
  };
4716
4891
 
4717
4892
  // src/components/LinkedAccounts/LinkedAccounts.tsx
4718
4893
  import classNames24 from "classnames";
4719
4894
  var COMPONENT_NAME2 = "linked-accounts";
4720
- var LinkedAccounts = ({ asWidget }) => {
4895
+ var LinkedAccounts = ({ asWidget, elevated }) => {
4721
4896
  const {
4722
4897
  data,
4723
4898
  isLoading,
4724
4899
  error,
4725
4900
  isValidating,
4726
- refetch,
4727
- addAccount,
4901
+ refetchAccounts,
4902
+ addConnection,
4728
4903
  unlinkAccount,
4729
4904
  renewLinkAccount
4730
4905
  } = useLinkedAccounts();
@@ -4736,7 +4911,7 @@ var LinkedAccounts = ({ asWidget }) => {
4736
4911
  "Layer__linked-accounts__new-account",
4737
4912
  asWidget && "--as-widget"
4738
4913
  );
4739
- return /* @__PURE__ */ React64.createElement(Container, { name: COMPONENT_NAME2 }, /* @__PURE__ */ React64.createElement(Header, { className: "Layer__linked-accounts__header" }, /* @__PURE__ */ React64.createElement(
4914
+ return /* @__PURE__ */ React64.createElement(Container, { name: COMPONENT_NAME2, elevated }, /* @__PURE__ */ React64.createElement(Header, { className: "Layer__linked-accounts__header" }, /* @__PURE__ */ React64.createElement(
4740
4915
  Heading,
4741
4916
  {
4742
4917
  className: "Layer__linked-accounts__title",
@@ -4749,14 +4924,16 @@ var LinkedAccounts = ({ asWidget }) => {
4749
4924
  status: "failed" /* failed */,
4750
4925
  title: "Something went wrong",
4751
4926
  description: "We couldn\u2019t load your data.",
4752
- onRefresh: () => refetch(),
4927
+ onRefresh: () => refetchAccounts(),
4753
4928
  isLoading: isValidating
4754
4929
  }
4755
4930
  ) : null, !error && !isLoading ? /* @__PURE__ */ React64.createElement("div", { className: "Layer__linked-accounts__list" }, data?.map((account, index) => /* @__PURE__ */ React64.createElement(
4756
4931
  LinkedAccountOptions,
4757
4932
  {
4758
4933
  key: `linked-acc-${index}`,
4759
- config: linkedAccountOptionsConfig
4934
+ config: linkedAccountOptionsConfig,
4935
+ accountId: account.external_account_external_id,
4936
+ plaidItemId: "TODO"
4760
4937
  },
4761
4938
  /* @__PURE__ */ React64.createElement(LinkedAccountThumb, { account, asWidget })
4762
4939
  )), /* @__PURE__ */ React64.createElement(
@@ -4765,18 +4942,18 @@ var LinkedAccounts = ({ asWidget }) => {
4765
4942
  role: "button",
4766
4943
  tabIndex: 0,
4767
4944
  "aria-label": "new-account",
4768
- onClick: () => addAccount(),
4945
+ onClick: () => addConnection("PLAID"),
4769
4946
  className: linkedAccountsNewAccountClassName
4770
4947
  },
4771
- /* @__PURE__ */ React64.createElement("div", { className: "Layer__linked-accounts__new-account-label" }, /* @__PURE__ */ React64.createElement(PlusIcon_default, { size: 15 }), /* @__PURE__ */ React64.createElement(Text, { as: "span", size: "sm" }, "New account"))
4948
+ /* @__PURE__ */ React64.createElement("div", { className: "Layer__linked-accounts__new-account-label" }, /* @__PURE__ */ React64.createElement(PlusIcon_default, { size: 15 }), /* @__PURE__ */ React64.createElement(Text, { as: "span", size: "sm" }, "Add Account"))
4772
4949
  )) : null);
4773
4950
  };
4774
4951
 
4775
4952
  // src/components/ProfitAndLoss/ProfitAndLoss.tsx
4776
- import React74, { createContext as createContext2 } from "react";
4953
+ import React80, { createContext as createContext2 } from "react";
4777
4954
 
4778
4955
  // src/hooks/useProfitAndLoss/useProfitAndLoss.tsx
4779
- import { useMemo as useMemo3, useState as useState12 } from "react";
4956
+ import { useMemo as useMemo3, useState as useState13 } from "react";
4780
4957
 
4781
4958
  // src/utils/profitAndLossUtils.ts
4782
4959
  var doesLineItemQualifies = (item) => {
@@ -4844,17 +5021,17 @@ var useProfitAndLoss = ({
4844
5021
  endDate: endOfMonth(/* @__PURE__ */ new Date())
4845
5022
  }) => {
4846
5023
  const { auth, businessId, apiUrl } = useLayerContext();
4847
- const [startDate, setStartDate] = useState12(
5024
+ const [startDate, setStartDate] = useState13(
4848
5025
  initialStartDate || startOfMonth(Date.now())
4849
5026
  );
4850
- const [endDate, setEndDate] = useState12(
5027
+ const [endDate, setEndDate] = useState13(
4851
5028
  initialEndDate || endOfMonth(Date.now())
4852
5029
  );
4853
- const [filters, setFilters] = useState12({
5030
+ const [filters, setFilters] = useState13({
4854
5031
  expenses: void 0,
4855
5032
  revenue: void 0
4856
5033
  });
4857
- const [sidebarScope, setSidebarScope] = useState12(void 0);
5034
+ const [sidebarScope, setSidebarScope] = useState13(void 0);
4858
5035
  const {
4859
5036
  data: rawData,
4860
5037
  isLoading,
@@ -4877,13 +5054,50 @@ var useProfitAndLoss = ({
4877
5054
  })
4878
5055
  );
4879
5056
  const { data, error } = rawData || {};
4880
- const { filteredData, filteredTotal } = useMemo3(() => {
5057
+ const { filteredDataRevenue, filteredTotalRevenue } = useMemo3(() => {
5058
+ if (!data) {
5059
+ return { filteredDataRevenue: [], filteredTotalRevenue: void 0 };
5060
+ }
5061
+ const items = collectRevenueItems(data);
5062
+ const filtered = items.map((x) => {
5063
+ if (filters["revenue"]?.types && filters["revenue"].types.length > 0 && !filters["revenue"]?.types?.includes(x.type)) {
5064
+ return {
5065
+ ...x,
5066
+ hidden: true
5067
+ };
5068
+ }
5069
+ return x;
5070
+ });
5071
+ const sorted = filtered.sort((a, b) => {
5072
+ switch (filters["revenue"]?.sortBy) {
5073
+ case "category":
5074
+ if (filters["revenue"]?.sortDirection === "asc") {
5075
+ return a.display_name.localeCompare(b.display_name);
5076
+ }
5077
+ return b.display_name.localeCompare(a.display_name);
5078
+ case "type":
5079
+ if (filters["revenue"]?.sortDirection === "asc") {
5080
+ return a.type.localeCompare(b.type);
5081
+ }
5082
+ return b.type.localeCompare(a.type);
5083
+ default:
5084
+ if (filters["revenue"]?.sortDirection === "asc") {
5085
+ return a.value - b.value;
5086
+ }
5087
+ return b.value - a.value;
5088
+ }
5089
+ });
5090
+ const total = sorted.filter((x) => !x.hidden).reduce((x, { value }) => x + value, 0);
5091
+ const withShare = applyShare(sorted, total);
5092
+ return { filteredDataRevenue: withShare, filteredTotalRevenue: total };
5093
+ }, [data, startDate, filters, sidebarScope]);
5094
+ const { filteredDataExpenses, filteredTotalExpenses } = useMemo3(() => {
4881
5095
  if (!data) {
4882
- return { filteredData: [], filteredTotal: void 0 };
5096
+ return { filteredDataExpenses: [], filteredTotalExpenses: void 0 };
4883
5097
  }
4884
- const items = sidebarScope === "revenue" ? collectRevenueItems(data) : collectExpensesItems(data);
5098
+ const items = collectExpensesItems(data);
4885
5099
  const filtered = items.map((x) => {
4886
- if (sidebarScope && filters[sidebarScope]?.types && filters[sidebarScope].types.length > 0 && !filters[sidebarScope]?.types?.includes(x.type)) {
5100
+ if (filters["expenses"]?.types && filters["expenses"].types.length > 0 && !filters["expenses"]?.types?.includes(x.type)) {
4887
5101
  return {
4888
5102
  ...x,
4889
5103
  hidden: true
@@ -4892,19 +5106,19 @@ var useProfitAndLoss = ({
4892
5106
  return x;
4893
5107
  });
4894
5108
  const sorted = filtered.sort((a, b) => {
4895
- switch (filters[sidebarScope ?? "expenses"]?.sortBy) {
5109
+ switch (filters["expenses"]?.sortBy) {
4896
5110
  case "category":
4897
- if (filters[sidebarScope ?? "expenses"]?.sortDirection === "asc") {
5111
+ if (filters["expenses"]?.sortDirection === "asc") {
4898
5112
  return a.display_name.localeCompare(b.display_name);
4899
5113
  }
4900
5114
  return b.display_name.localeCompare(a.display_name);
4901
5115
  case "type":
4902
- if (filters[sidebarScope ?? "expenses"]?.sortDirection === "asc") {
5116
+ if (filters["expenses"]?.sortDirection === "asc") {
4903
5117
  return a.type.localeCompare(b.type);
4904
5118
  }
4905
5119
  return b.type.localeCompare(a.type);
4906
5120
  default:
4907
- if (filters[sidebarScope ?? "expenses"]?.sortDirection === "asc") {
5121
+ if (filters["expenses"]?.sortDirection === "asc") {
4908
5122
  return a.value - b.value;
4909
5123
  }
4910
5124
  return b.value - a.value;
@@ -4912,7 +5126,7 @@ var useProfitAndLoss = ({
4912
5126
  });
4913
5127
  const total = sorted.filter((x) => !x.hidden).reduce((x, { value }) => x + value, 0);
4914
5128
  const withShare = applyShare(sorted, total);
4915
- return { filteredData: withShare, filteredTotal: total };
5129
+ return { filteredDataExpenses: withShare, filteredTotalExpenses: total };
4916
5130
  }, [data, startDate, filters, sidebarScope]);
4917
5131
  const changeDateRange = ({
4918
5132
  startDate: newStartDate,
@@ -4945,8 +5159,10 @@ var useProfitAndLoss = ({
4945
5159
  };
4946
5160
  return {
4947
5161
  data,
4948
- filteredData,
4949
- filteredTotal,
5162
+ filteredDataRevenue,
5163
+ filteredTotalRevenue,
5164
+ filteredDataExpenses,
5165
+ filteredTotalExpenses,
4950
5166
  isLoading,
4951
5167
  isValidating,
4952
5168
  error: error || rawError,
@@ -4962,7 +5178,7 @@ var useProfitAndLoss = ({
4962
5178
  };
4963
5179
 
4964
5180
  // src/components/ProfitAndLossChart/ProfitAndLossChart.tsx
4965
- import React66, { useContext as useContext2, useMemo as useMemo4, useState as useState13 } from "react";
5181
+ import React66, { useContext as useContext2, useMemo as useMemo4, useState as useState14 } from "react";
4966
5182
 
4967
5183
  // src/utils/format.ts
4968
5184
  var capitalizeFirstLetter = (text) => text.charAt(0).toUpperCase() + text.slice(1);
@@ -4998,9 +5214,12 @@ var formatPercent = (value, options) => {
4998
5214
  ...options
4999
5215
  });
5000
5216
  };
5217
+ var humanizeEnum = (text) => {
5218
+ return capitalizeFirstLetter(text.replace(/_/gi, " ").toLowerCase());
5219
+ };
5001
5220
 
5002
5221
  // src/components/ProfitAndLossChart/Indicator.tsx
5003
- import React65, { useEffect as useEffect9 } from "react";
5222
+ import React65, { useEffect as useEffect10 } from "react";
5004
5223
  var emptyViewBox = { x: 0, y: 0, width: 0, height: 0 };
5005
5224
  var Indicator = ({
5006
5225
  viewBox = {},
@@ -5017,7 +5236,7 @@ var Indicator = ({
5017
5236
  const multiplier = width > 12 ? 1.2 : 1;
5018
5237
  const xOffset = (boxWidth * multiplier - boxWidth) / 2;
5019
5238
  const borderRadius = width > 16 ? 8 : width / 2;
5020
- useEffect9(() => {
5239
+ useEffect10(() => {
5021
5240
  setAnimateFrom(animateTo);
5022
5241
  }, [animateTo]);
5023
5242
  const actualX = animateFrom === -1 ? animateTo : animateFrom;
@@ -5187,7 +5406,7 @@ var ProfitAndLossChart = () => {
5187
5406
  ...monthData.map((m) => m?.net_profit)
5188
5407
  ]
5189
5408
  );
5190
- const [animateFrom, setAnimateFrom] = useState13(-1);
5409
+ const [animateFrom, setAnimateFrom] = useState14(-1);
5191
5410
  return /* @__PURE__ */ React66.createElement(
5192
5411
  ResponsiveContainer,
5193
5412
  {
@@ -5295,19 +5514,19 @@ var ProfitAndLossChart = () => {
5295
5514
  };
5296
5515
 
5297
5516
  // src/components/ProfitAndLossDatePicker/ProfitAndLossDatePicker.tsx
5298
- import React67, { useContext as useContext3, useState as useState14, useEffect as useEffect10 } from "react";
5517
+ import React67, { useContext as useContext3, useState as useState15, useEffect as useEffect11 } from "react";
5299
5518
  import { add, endOfMonth as endOfMonth3, format as format5, startOfMonth as startOfMonth3 } from "date-fns";
5300
5519
  var ProfitAndLossDatePicker = () => {
5301
5520
  const { changeDateRange, dateRange } = useContext3(ProfitAndLoss.Context);
5302
- const [isAnimating, setIsAnimating] = useState14(false);
5303
- const [localDate, setLocalDate] = useState14(dateRange.startDate);
5304
- const [nextOpacity, setNextOpacity] = useState14(0);
5305
- const [currentOpacity, setCurrentOpacity] = useState14(1);
5306
- const [transformStyle, setTransformStyle] = useState14({
5521
+ const [isAnimating, setIsAnimating] = useState15(false);
5522
+ const [localDate, setLocalDate] = useState15(dateRange.startDate);
5523
+ const [nextOpacity, setNextOpacity] = useState15(0);
5524
+ const [currentOpacity, setCurrentOpacity] = useState15(1);
5525
+ const [transformStyle, setTransformStyle] = useState15({
5307
5526
  transform: "translateX(33%)",
5308
5527
  transition: "ease"
5309
5528
  });
5310
- useEffect10(() => {
5529
+ useEffect11(() => {
5311
5530
  if (dateRange.startDate !== localDate && !isAnimating) {
5312
5531
  setLocalDate(dateRange.startDate);
5313
5532
  setTransformStyle({ transform: "translateX(33%)", transition: "none" });
@@ -5401,26 +5620,44 @@ var ProfitAndLossDatePicker = () => {
5401
5620
  );
5402
5621
  };
5403
5622
 
5404
- // src/components/ProfitAndLossSummaries/ProfitAndLossSummaries.tsx
5405
- import React70, { useContext as useContext4, useMemo as useMemo5 } from "react";
5623
+ // src/components/ProfitAndLossDetailedCharts/ProfitAndLossDetailedCharts.tsx
5624
+ import React73, { useContext as useContext4, useState as useState16 } from "react";
5406
5625
 
5407
- // src/components/SkeletonLoader/SkeletonLoader.tsx
5408
- import React68 from "react";
5409
- import classNames25 from "classnames";
5410
- var SkeletonLoader = ({
5411
- height,
5412
- width,
5413
- className
5414
- }) => {
5415
- const baseClassName = classNames25(
5416
- "Layer__skeleton-loader Layer__anim--skeleton-loading",
5417
- className
5418
- );
5419
- return /* @__PURE__ */ React68.createElement("div", { className: baseClassName, style: { width, height } });
5420
- };
5626
+ // src/icons/X.tsx
5627
+ import * as React68 from "react";
5628
+ var X = ({ size = 18, ...props }) => /* @__PURE__ */ React68.createElement(
5629
+ "svg",
5630
+ {
5631
+ xmlns: "http://www.w3.org/2000/svg",
5632
+ viewBox: "0 0 18 18",
5633
+ fill: "none",
5634
+ ...props,
5635
+ width: size,
5636
+ height: size
5637
+ },
5638
+ /* @__PURE__ */ React68.createElement(
5639
+ "path",
5640
+ {
5641
+ d: "M13.5 4.5L4.5 13.5",
5642
+ stroke: "currentColor",
5643
+ strokeLinecap: "round",
5644
+ strokeLinejoin: "round"
5645
+ }
5646
+ ),
5647
+ /* @__PURE__ */ React68.createElement(
5648
+ "path",
5649
+ {
5650
+ d: "M4.5 4.5L13.5 13.5",
5651
+ stroke: "currentColor",
5652
+ strokeLinecap: "round",
5653
+ strokeLinejoin: "round"
5654
+ }
5655
+ )
5656
+ );
5657
+ var X_default = X;
5421
5658
 
5422
- // src/components/ProfitAndLossSummaries/MiniChart.tsx
5423
- import React69 from "react";
5659
+ // src/components/ProfitAndLossDetailedCharts/DetailedChart.tsx
5660
+ import React69, { useMemo as useMemo5 } from "react";
5424
5661
 
5425
5662
  // src/config/charts.ts
5426
5663
  var INACTIVE_OPACITY_LEVELS = [
@@ -5508,1619 +5745,2305 @@ var DEFAULT_CHART_COLORS = [
5508
5745
  }
5509
5746
  ];
5510
5747
 
5511
- // src/components/ProfitAndLossSummaries/MiniChart.tsx
5512
- import { PieChart, Pie, Cell as Cell2 } from "recharts";
5513
- var MiniChart = ({ data }) => {
5514
- return /* @__PURE__ */ React69.createElement(PieChart, { width: 48, height: 48, className: "mini-chart" }, /* @__PURE__ */ React69.createElement(
5748
+ // src/components/ProfitAndLossDetailedCharts/DetailedChart.tsx
5749
+ import {
5750
+ PieChart,
5751
+ Pie,
5752
+ Cell as Cell2,
5753
+ ResponsiveContainer as ResponsiveContainer2,
5754
+ Label,
5755
+ Text as ChartText
5756
+ } from "recharts";
5757
+ var DetailedChart = ({
5758
+ filteredData,
5759
+ filteredTotal,
5760
+ hoveredItem,
5761
+ setHoveredItem,
5762
+ sidebarScope,
5763
+ date,
5764
+ isLoading
5765
+ }) => {
5766
+ const chartData = useMemo5(() => {
5767
+ if (!filteredData) {
5768
+ return [];
5769
+ }
5770
+ return filteredData.map((x) => {
5771
+ if (x.hidden) {
5772
+ return {
5773
+ name: x.display_name,
5774
+ value: 0
5775
+ };
5776
+ }
5777
+ return {
5778
+ name: x.display_name,
5779
+ value: x.value
5780
+ };
5781
+ });
5782
+ }, [filteredData, isLoading]);
5783
+ const noValue = chartData.length === 0 || !chartData.find((x) => x.value !== 0);
5784
+ return /* @__PURE__ */ React69.createElement("div", { className: "chart-field" }, /* @__PURE__ */ React69.createElement("div", { className: "header--tablet" }, /* @__PURE__ */ React69.createElement(Text, { size: "lg" /* lg */, weight: "bold" /* bold */, className: "title" }, humanizeTitle(sidebarScope)), /* @__PURE__ */ React69.createElement(ProfitAndLossDatePicker, null)), /* @__PURE__ */ React69.createElement("div", { className: "chart-container" }, /* @__PURE__ */ React69.createElement(ResponsiveContainer2, null, /* @__PURE__ */ React69.createElement(PieChart, null, !isLoading && !noValue ? /* @__PURE__ */ React69.createElement(
5515
5785
  Pie,
5516
5786
  {
5517
- data,
5787
+ data: chartData,
5518
5788
  dataKey: "value",
5519
5789
  nameKey: "name",
5520
5790
  cx: "50%",
5521
5791
  cy: "50%",
5522
- innerRadius: 10,
5523
- outerRadius: 16,
5524
- paddingAngle: 0.2,
5792
+ innerRadius: 105,
5793
+ outerRadius: 120,
5794
+ paddingAngle: 0.5,
5525
5795
  fill: "#8884d8",
5526
- width: 24,
5527
- height: 24,
5528
- animationDuration: 250,
5796
+ animationDuration: 200,
5529
5797
  animationEasing: "ease-in-out"
5530
5798
  },
5531
- data.map((entry, index) => {
5799
+ chartData.map((entry, index) => {
5532
5800
  const colorConfig = DEFAULT_CHART_COLORS[index % DEFAULT_CHART_COLORS.length];
5801
+ let fill = colorConfig.color;
5802
+ let opacity = colorConfig.opacity;
5803
+ let active = true;
5804
+ if (hoveredItem && entry.name !== hoveredItem) {
5805
+ active = false;
5806
+ fill = void 0;
5807
+ opacity = INACTIVE_OPACITY_LEVELS[index % INACTIVE_OPACITY_LEVELS.length];
5808
+ }
5533
5809
  return /* @__PURE__ */ React69.createElement(
5534
5810
  Cell2,
5535
5811
  {
5536
5812
  key: `cell-${index}`,
5537
- className: `Layer__profit-and-loss-detailed-charts__pie`,
5538
- fill: entry.name === "placeholder" ? "#e6e6e6" : colorConfig.color,
5539
- opacity: colorConfig.opacity
5813
+ className: `Layer__profit-and-loss-detailed-charts__pie ${hoveredItem && active ? "active" : "inactive"}`,
5814
+ style: { fill },
5815
+ opacity,
5816
+ onMouseEnter: () => setHoveredItem(entry.name),
5817
+ onMouseLeave: () => setHoveredItem(void 0)
5540
5818
  }
5541
5819
  );
5542
- })
5543
- ));
5544
- };
5545
-
5546
- // src/components/ProfitAndLossSummaries/ProfitAndLossSummaries.tsx
5547
- import classNames26 from "classnames";
5548
- var CHART_PLACEHOLDER = [
5549
- {
5550
- name: "placeholder",
5551
- display_name: "placeholder",
5552
- value: 1,
5553
- type: "placeholder",
5554
- share: 1
5555
- }
5556
- ];
5557
- var buildMiniChartData = (scope, data) => {
5558
- if (!data) {
5559
- return CHART_PLACEHOLDER;
5560
- }
5561
- let items = [];
5562
- switch (scope) {
5563
- case "revenue":
5564
- items = collectRevenueItems(data);
5565
- break;
5566
- default:
5567
- items = collectExpensesItems(data);
5568
- }
5569
- if (!items || items.length === 0 || !items.find((x) => Math.abs(x.value) !== 0)) {
5570
- return CHART_PLACEHOLDER;
5571
- }
5572
- return items.slice();
5573
- };
5574
- var ProfitAndLossSummaries = ({
5575
- vertical,
5576
- revenueLabel = "Revenue"
5577
- }) => {
5578
- const {
5579
- data: storedData,
5580
- isLoading,
5581
- setSidebarScope,
5582
- sidebarScope
5583
- } = useContext4(ProfitAndLoss.Context);
5584
- const expensesChartData = useMemo5(() => {
5585
- return buildMiniChartData("expenses", storedData);
5586
- }, [storedData]);
5587
- const revenueChartData = useMemo5(() => {
5588
- return buildMiniChartData("revenue", storedData);
5589
- }, [storedData]);
5590
- const data = storedData ? storedData : { income: { value: NaN }, net_profit: NaN };
5591
- const incomeDirectionClass = (data.income.value ?? NaN) < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--positive";
5592
- const expensesDirectionClass = (data?.income?.value ?? NaN) - data.net_profit < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--positive";
5593
- const netProfitDirectionClass = data.net_profit < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--positive";
5594
- return /* @__PURE__ */ React70.createElement(
5595
- "div",
5596
- {
5597
- className: `Layer__profit-and-loss-summaries ${vertical ? "flex-col" : ""}`
5598
- },
5599
- /* @__PURE__ */ React70.createElement(
5600
- "div",
5820
+ }),
5821
+ /* @__PURE__ */ React69.createElement(
5822
+ Label,
5601
5823
  {
5602
- className: classNames26(
5603
- "Layer__profit-and-loss-summaries__summary Layer__actionable",
5604
- "Layer__profit-and-loss-summaries__summary--income",
5605
- sidebarScope === "revenue" ? "active" : ""
5606
- ),
5607
- onClick: () => setSidebarScope("revenue")
5608
- },
5609
- /* @__PURE__ */ React70.createElement(MiniChart, { data: revenueChartData }),
5610
- /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__text" }, /* @__PURE__ */ React70.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, revenueLabel), isLoading || storedData === void 0 ? /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__loader" }, /* @__PURE__ */ React70.createElement(SkeletonLoader, null)) : /* @__PURE__ */ React70.createElement(
5611
- "span",
5612
- {
5613
- className: `Layer__profit-and-loss-summaries__amount ${incomeDirectionClass}`
5614
- },
5615
- centsToDollars(Math.abs(data?.income?.value ?? NaN))
5616
- ))
5824
+ position: "center",
5825
+ value: "Total",
5826
+ className: "pie-center-label-title",
5827
+ content: (props) => {
5828
+ const { cx, cy } = props.viewBox ?? {
5829
+ cx: 0,
5830
+ cy: 0
5831
+ };
5832
+ const positioningProps = {
5833
+ x: cx,
5834
+ y: (cy || 0) - 15,
5835
+ textAnchor: "middle",
5836
+ verticalAnchor: "middle"
5837
+ };
5838
+ let text = "Total";
5839
+ if (hoveredItem) {
5840
+ text = hoveredItem;
5841
+ }
5842
+ return /* @__PURE__ */ React69.createElement(
5843
+ ChartText,
5844
+ {
5845
+ ...positioningProps,
5846
+ className: "pie-center-label__title"
5847
+ },
5848
+ text
5849
+ );
5850
+ }
5851
+ }
5617
5852
  ),
5618
- /* @__PURE__ */ React70.createElement(
5619
- "div",
5853
+ /* @__PURE__ */ React69.createElement(
5854
+ Label,
5620
5855
  {
5621
- className: classNames26(
5622
- "Layer__profit-and-loss-summaries__summary Layer__actionable",
5623
- "Layer__profit-and-loss-summaries__summary--expenses",
5624
- sidebarScope === "expenses" ? "active" : ""
5625
- ),
5626
- onClick: () => setSidebarScope("expenses")
5627
- },
5628
- /* @__PURE__ */ React70.createElement(MiniChart, { data: expensesChartData }),
5629
- /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__text" }, /* @__PURE__ */ React70.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Expenses"), isLoading || storedData === void 0 ? /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__loader" }, /* @__PURE__ */ React70.createElement(SkeletonLoader, { className: "Layer__profit-and-loss-summaries__loader" })) : /* @__PURE__ */ React70.createElement(
5630
- "span",
5631
- {
5632
- className: `Layer__profit-and-loss-summaries__amount ${expensesDirectionClass}`
5633
- },
5634
- centsToDollars(
5635
- Math.abs((data.income.value ?? 0) - data.net_profit)
5636
- )
5637
- ))
5856
+ position: "center",
5857
+ value: "Total",
5858
+ className: "pie-center-label-title",
5859
+ content: (props) => {
5860
+ const { cx, cy } = props.viewBox ?? {
5861
+ cx: 0,
5862
+ cy: 0
5863
+ };
5864
+ const positioningProps = {
5865
+ x: cx,
5866
+ y: (cy || 0) + 5,
5867
+ textAnchor: "middle",
5868
+ verticalAnchor: "middle"
5869
+ };
5870
+ let value = filteredTotal;
5871
+ if (hoveredItem) {
5872
+ value = filteredData.find(
5873
+ (x) => x.display_name === hoveredItem
5874
+ )?.value;
5875
+ }
5876
+ return /* @__PURE__ */ React69.createElement(
5877
+ ChartText,
5878
+ {
5879
+ ...positioningProps,
5880
+ className: "pie-center-label__value"
5881
+ },
5882
+ `$${centsToDollars(value)}`
5883
+ );
5884
+ }
5885
+ }
5638
5886
  ),
5639
- /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__summary net-profit Layer__profit-and-loss-summaries__summary--net-profit" }, /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__text" }, /* @__PURE__ */ React70.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Net Profit"), isLoading || storedData === void 0 ? /* @__PURE__ */ React70.createElement("div", { className: "Layer__profit-and-loss-summaries__loader" }, /* @__PURE__ */ React70.createElement(SkeletonLoader, { className: "Layer__profit-and-loss-summaries__loader" })) : /* @__PURE__ */ React70.createElement(
5640
- "span",
5887
+ /* @__PURE__ */ React69.createElement(
5888
+ Label,
5641
5889
  {
5642
- className: `Layer__profit-and-loss-summaries__amount ${netProfitDirectionClass}`
5643
- },
5644
- centsToDollars(Math.abs(data.net_profit))
5645
- )))
5646
- );
5890
+ position: "center",
5891
+ value: "Total",
5892
+ className: "pie-center-label-title",
5893
+ content: (props) => {
5894
+ const { cx, cy } = props.viewBox ?? {
5895
+ cx: 0,
5896
+ cy: 0
5897
+ };
5898
+ const positioningProps = {
5899
+ x: cx,
5900
+ y: (cy || 0) + 25,
5901
+ height: 20,
5902
+ textAnchor: "middle",
5903
+ verticalAnchor: "middle"
5904
+ };
5905
+ if (hoveredItem) {
5906
+ return /* @__PURE__ */ React69.createElement(
5907
+ ChartText,
5908
+ {
5909
+ ...positioningProps,
5910
+ className: "pie-center-label__share"
5911
+ },
5912
+ `${formatPercent(
5913
+ filteredData.find(
5914
+ (x) => x.display_name === hoveredItem
5915
+ )?.share
5916
+ )}%`
5917
+ );
5918
+ }
5919
+ return;
5920
+ }
5921
+ }
5922
+ )
5923
+ ) : null, !isLoading && noValue ? /* @__PURE__ */ React69.createElement(
5924
+ Pie,
5925
+ {
5926
+ data: [{ name: "Total", value: 1 }],
5927
+ dataKey: "value",
5928
+ nameKey: "name",
5929
+ cx: "50%",
5930
+ cy: "50%",
5931
+ innerRadius: 105,
5932
+ outerRadius: 120,
5933
+ paddingAngle: 0,
5934
+ fill: "#F8F8FA",
5935
+ animationDuration: 200,
5936
+ animationEasing: "ease-in-out"
5937
+ },
5938
+ /* @__PURE__ */ React69.createElement(
5939
+ Label,
5940
+ {
5941
+ position: "center",
5942
+ value: "Total",
5943
+ className: "pie-center-label-title",
5944
+ content: (props) => {
5945
+ const { cx, cy } = props.viewBox ?? {
5946
+ cx: 0,
5947
+ cy: 0
5948
+ };
5949
+ const positioningProps = {
5950
+ x: cx,
5951
+ y: (cy || 0) - 15,
5952
+ textAnchor: "middle",
5953
+ verticalAnchor: "middle"
5954
+ };
5955
+ let text = "Total";
5956
+ if (hoveredItem) {
5957
+ text = hoveredItem;
5958
+ }
5959
+ return /* @__PURE__ */ React69.createElement(
5960
+ ChartText,
5961
+ {
5962
+ ...positioningProps,
5963
+ className: "pie-center-label__title"
5964
+ },
5965
+ text
5966
+ );
5967
+ }
5968
+ }
5969
+ ),
5970
+ /* @__PURE__ */ React69.createElement(
5971
+ Label,
5972
+ {
5973
+ position: "center",
5974
+ value: "Total",
5975
+ className: "pie-center-label-title",
5976
+ content: (props) => {
5977
+ const { cx, cy } = props.viewBox ?? {
5978
+ cx: 0,
5979
+ cy: 0
5980
+ };
5981
+ const positioningProps = {
5982
+ x: cx,
5983
+ y: (cy || 0) + 5,
5984
+ textAnchor: "middle",
5985
+ verticalAnchor: "middle"
5986
+ };
5987
+ let value = filteredTotal;
5988
+ if (hoveredItem) {
5989
+ value = filteredData.find(
5990
+ (x) => x.display_name === hoveredItem
5991
+ )?.value;
5992
+ }
5993
+ return /* @__PURE__ */ React69.createElement(
5994
+ ChartText,
5995
+ {
5996
+ ...positioningProps,
5997
+ className: "pie-center-label__value"
5998
+ },
5999
+ `$${centsToDollars(value)}`
6000
+ );
6001
+ }
6002
+ }
6003
+ )
6004
+ ) : null, isLoading ? /* @__PURE__ */ React69.createElement(
6005
+ Pie,
6006
+ {
6007
+ data: [{ name: "loading...", value: 1 }],
6008
+ dataKey: "value",
6009
+ nameKey: "name",
6010
+ cx: "50%",
6011
+ cy: "50%",
6012
+ innerRadius: 105,
6013
+ outerRadius: 120,
6014
+ paddingAngle: 0,
6015
+ fill: "#F8F8FA",
6016
+ animationDuration: 200,
6017
+ animationEasing: "ease-in-out"
6018
+ }
6019
+ ) : null))));
5647
6020
  };
5648
6021
 
5649
- // src/components/ProfitAndLossTable/ProfitAndLossTable.tsx
5650
- import React73, { useContext as useContext5 } from "react";
5651
-
5652
- // src/components/ProfitAndLossRow/ProfitAndLossRow.tsx
5653
- import React72, { useState as useState15 } from "react";
6022
+ // src/components/ProfitAndLossDetailedCharts/DetailedTable.tsx
6023
+ import React71 from "react";
5654
6024
 
5655
- // src/icons/PieChart.tsx
5656
- import * as React71 from "react";
5657
- var PieChart2 = ({ size = 12, ...props }) => /* @__PURE__ */ React71.createElement(
6025
+ // src/icons/SortArrows.tsx
6026
+ import * as React70 from "react";
6027
+ var SortArrows = ({ size = 13, ...props }) => /* @__PURE__ */ React70.createElement(
5658
6028
  "svg",
5659
6029
  {
5660
6030
  xmlns: "http://www.w3.org/2000/svg",
5661
- viewBox: "0 0 12 12",
6031
+ viewBox: "0 0 12 13",
5662
6032
  fill: "none",
5663
6033
  ...props,
5664
6034
  width: size,
5665
6035
  height: size
5666
6036
  },
5667
- /* @__PURE__ */ React71.createElement("g", null, /* @__PURE__ */ React71.createElement(
6037
+ /* @__PURE__ */ React70.createElement("g", { "clip-path": "url(#clip0_1758_75388)" }, /* @__PURE__ */ React70.createElement(
5668
6038
  "path",
5669
6039
  {
5670
- d: "M10.2213 7.78271C9.92969 8.47226 9.47363 9.07989 8.89297 9.55247C8.3123 10.0251 7.62471 10.3482 6.89031 10.4936C6.1559 10.6391 5.39705 10.6024 4.68009 10.3869C3.96313 10.1713 3.30989 9.78337 2.77749 9.25701C2.24509 8.73065 1.84973 8.08189 1.62598 7.36744C1.40223 6.65298 1.3569 5.8946 1.49396 5.15858C1.63102 4.42257 1.94629 3.73133 2.41221 3.14531C2.87813 2.55928 3.48051 2.09631 4.16669 1.79688",
6040
+ d: "M1.33325 8.5L3.99992 11.1667L6.66659 8.5",
5671
6041
  stroke: "currentColor",
5672
6042
  strokeLinecap: "round",
5673
- strokeLinejoin: "round"
6043
+ strokeLinejoin: "round",
6044
+ className: "desc-arrow"
5674
6045
  }
5675
- ), /* @__PURE__ */ React71.createElement(
6046
+ ), /* @__PURE__ */ React70.createElement(
5676
6047
  "path",
5677
6048
  {
5678
- d: "M10.5833 6.00033C10.5833 5.39843 10.4648 4.80244 10.2344 4.24636C10.0041 3.69028 9.66651 3.18502 9.24091 2.75942C8.8153 2.33382 8.31004 1.99621 7.75397 1.76588C7.19789 1.53554 6.60189 1.41699 6 1.41699V6.00033H10.5833Z",
6049
+ d: "M4 2.5L4 11.1667",
5679
6050
  stroke: "currentColor",
5680
6051
  strokeLinecap: "round",
5681
- strokeLinejoin: "round"
6052
+ strokeLinejoin: "round",
6053
+ className: "desc-arrow"
5682
6054
  }
5683
- ))
6055
+ ), /* @__PURE__ */ React70.createElement(
6056
+ "path",
6057
+ {
6058
+ d: "M5.99988 5.16602L8.66654 2.49935L11.3332 5.16602",
6059
+ stroke: "currentColor",
6060
+ strokeLinecap: "round",
6061
+ strokeLinejoin: "round",
6062
+ className: "asc-arrow"
6063
+ }
6064
+ ), /* @__PURE__ */ React70.createElement(
6065
+ "path",
6066
+ {
6067
+ d: "M8.66663 11.166L8.66663 2.49935",
6068
+ stroke: "currentColor",
6069
+ strokeLinecap: "round",
6070
+ strokeLinejoin: "round",
6071
+ className: "asc-arrow"
6072
+ }
6073
+ )),
6074
+ /* @__PURE__ */ React70.createElement("defs", null, /* @__PURE__ */ React70.createElement("clipPath", { id: "clip0_1758_75388" }, /* @__PURE__ */ React70.createElement(
6075
+ "rect",
6076
+ {
6077
+ width: "12",
6078
+ height: "12",
6079
+ fill: "white",
6080
+ transform: "translate(0 0.5)"
6081
+ }
6082
+ )))
5684
6083
  );
5685
- var PieChart_default = PieChart2;
6084
+ var SortArrows_default = SortArrows;
5686
6085
 
5687
- // src/components/ProfitAndLossRow/ProfitAndLossRow.tsx
5688
- var ProfitAndLossRow = ({
5689
- variant,
5690
- lineItem,
5691
- depth = 0,
5692
- maxDepth = 1,
5693
- direction = "DEBIT" /* DEBIT */,
5694
- lockExpanded = false,
5695
- scope,
5696
- setSidebarScope
6086
+ // src/components/ProfitAndLossDetailedCharts/DetailedTable.tsx
6087
+ import classNames25 from "classnames";
6088
+ var DetailedTable = ({
6089
+ filteredData,
6090
+ sidebarScope,
6091
+ filters,
6092
+ sortBy,
6093
+ hoveredItem,
6094
+ setHoveredItem
5697
6095
  }) => {
5698
- if (!lineItem) {
5699
- return null;
5700
- }
5701
- const { value, display_name, line_items } = lineItem;
5702
- const [expanded, setExpanded] = useState15(true);
5703
- const amount = value ?? 0;
5704
- const amountString = centsToDollars(Math.abs(amount));
5705
- const labelClasses = [
5706
- "Layer__profit-and-loss-row",
5707
- "Layer__profit-and-loss-row__label"
5708
- ];
5709
- const valueClasses = [
5710
- "Layer__profit-and-loss-row",
5711
- "Layer__profit-and-loss-row__value"
5712
- ];
5713
- const positive = amount === 0 || direction === "CREDIT" /* CREDIT */ && amount > 0 || direction === "DEBIT" /* DEBIT */ && amount < 0;
5714
- valueClasses.push(
5715
- positive ? "Layer__profit-and-loss-row__value--amount-positive" : "Layer__profit-and-loss-row__value--amount-negative"
5716
- );
5717
- labelClasses.push(`Layer__profit-and-loss-row__label--depth-${depth}`);
5718
- valueClasses.push(`Layer__profit-and-loss-row__value--depth-${depth}`);
5719
- variant && labelClasses.push(`Layer__profit-and-loss-row__label--variant-${variant}`);
5720
- variant && valueClasses.push(`Layer__profit-and-loss-row__value--variant-${variant}`);
5721
- const toggleExpanded = () => setExpanded(!expanded);
5722
- const canGoDeeper = depth < maxDepth;
5723
- const hasChildren = (line_items?.length ?? 0) > 0;
5724
- const displayChildren = hasChildren && canGoDeeper;
5725
- labelClasses.push(
5726
- `Layer__profit-and-loss-row__label--display-children-${displayChildren}`
5727
- );
5728
- valueClasses.push(
5729
- `Layer__profit-and-loss-row__value--display-children-${displayChildren}`
5730
- );
5731
- displayChildren && expanded && labelClasses.push("Layer__profit-and-loss-row__label--expanded");
5732
- displayChildren && expanded && valueClasses.push("Layer__profit-and-loss-row__value--expanded");
5733
- return /* @__PURE__ */ React72.createElement(React72.Fragment, null, /* @__PURE__ */ React72.createElement(
5734
- "div",
6096
+ const buildColClass = (column) => {
6097
+ return classNames25(
6098
+ "Layer__sortable-col",
6099
+ sidebarScope && filters[sidebarScope]?.sortBy === column ? `sort--${(sidebarScope && filters[sidebarScope]?.sortDirection) ?? "desc"}` : ""
6100
+ );
6101
+ };
6102
+ return /* @__PURE__ */ React71.createElement("div", { className: "details-container" }, /* @__PURE__ */ React71.createElement("div", { className: "table" }, /* @__PURE__ */ React71.createElement("table", null, /* @__PURE__ */ React71.createElement("thead", null, /* @__PURE__ */ React71.createElement("tr", null, /* @__PURE__ */ React71.createElement(
6103
+ "th",
5735
6104
  {
5736
- className: labelClasses.join(" "),
5737
- onClick: () => !lockExpanded && toggleExpanded()
6105
+ className: buildColClass("category"),
6106
+ onClick: () => sortBy(sidebarScope ?? "expenses", "category")
5738
6107
  },
5739
- /* @__PURE__ */ React72.createElement("span", { className: "Layer__profit-and-loss-row__label__title" }, !lockExpanded && variant !== "summation" ? /* @__PURE__ */ React72.createElement(
5740
- ChevronDownFill_default,
5741
- {
5742
- size: 16,
5743
- className: "Layer__profit-and-loss-row__label__chevron"
5744
- }
5745
- ) : null, /* @__PURE__ */ React72.createElement(Text, null, display_name)),
5746
- setSidebarScope && /* @__PURE__ */ React72.createElement(
5747
- "span",
5748
- {
5749
- className: "Layer__profit-and-loss-row__detailed-chart-btn",
5750
- onClick: (e) => {
5751
- e.stopPropagation();
5752
- setSidebarScope && setSidebarScope(scope ?? "expenses");
5753
- }
5754
- },
5755
- /* @__PURE__ */ React72.createElement(PieChart_default, null)
5756
- )
5757
- ), /* @__PURE__ */ React72.createElement("div", { className: valueClasses.join(" ") }, /* @__PURE__ */ React72.createElement(Text, null, amountString)), canGoDeeper && hasChildren && /* @__PURE__ */ React72.createElement(
5758
- "div",
6108
+ "Expense/Sale ",
6109
+ /* @__PURE__ */ React71.createElement(SortArrows_default, { className: "Layer__sort-arrows" })
6110
+ ), /* @__PURE__ */ React71.createElement(
6111
+ "th",
5759
6112
  {
5760
- className: `Layer__profit-and-loss-row__children ${expanded && "Layer__profit-and-loss-row__children--expanded"}`
6113
+ className: buildColClass("type"),
6114
+ onClick: () => sortBy(sidebarScope ?? "expenses", "type")
5761
6115
  },
5762
- /* @__PURE__ */ React72.createElement("div", { className: "Layer__profit-and-loss-row__children--content" }, (line_items || []).map((line_item) => /* @__PURE__ */ React72.createElement(
5763
- ProfitAndLossRow,
6116
+ "Type ",
6117
+ /* @__PURE__ */ React71.createElement(SortArrows_default, { className: "Layer__sort-arrows" })
6118
+ ), /* @__PURE__ */ React71.createElement("th", null), /* @__PURE__ */ React71.createElement(
6119
+ "th",
6120
+ {
6121
+ className: buildColClass("value"),
6122
+ onClick: () => sortBy(sidebarScope ?? "expenses", "value")
6123
+ },
6124
+ "Value ",
6125
+ /* @__PURE__ */ React71.createElement(SortArrows_default, { className: "Layer__sort-arrows" })
6126
+ ))), /* @__PURE__ */ React71.createElement("tbody", null, filteredData.filter((x) => !x.hidden).map((item, idx) => {
6127
+ const colorConfig = DEFAULT_CHART_COLORS[idx % DEFAULT_CHART_COLORS.length];
6128
+ return /* @__PURE__ */ React71.createElement(
6129
+ "tr",
5764
6130
  {
5765
- key: line_item.display_name,
5766
- lineItem: line_item,
5767
- depth: depth + 1,
5768
- maxDepth,
5769
- direction
5770
- }
5771
- )))
5772
- ));
6131
+ key: `pl-side-table-item-${idx}`,
6132
+ className: classNames25(
6133
+ "Layer__profit-and-loss-detailed-table__row",
6134
+ hoveredItem && hoveredItem === item.display_name ? "active" : ""
6135
+ ),
6136
+ onMouseEnter: () => setHoveredItem(item.display_name),
6137
+ onMouseLeave: () => setHoveredItem(void 0)
6138
+ },
6139
+ /* @__PURE__ */ React71.createElement("td", { className: "category-col" }, item.display_name),
6140
+ /* @__PURE__ */ React71.createElement("td", { className: "type-col" }, item.type),
6141
+ /* @__PURE__ */ React71.createElement("td", { className: "value-col" }, "$", centsToDollars(item.value)),
6142
+ /* @__PURE__ */ React71.createElement("td", { className: "share-col" }, /* @__PURE__ */ React71.createElement("span", { className: "share-cell-content" }, formatPercent(item.share), "%", /* @__PURE__ */ React71.createElement(
6143
+ "div",
6144
+ {
6145
+ className: "share-icon",
6146
+ style: {
6147
+ background: colorConfig.color,
6148
+ opacity: colorConfig.opacity
6149
+ }
6150
+ }
6151
+ )))
6152
+ );
6153
+ })))));
5773
6154
  };
5774
6155
 
5775
- // src/components/ProfitAndLossTable/empty_profit_and_loss_report.ts
5776
- var empty_profit_and_loss_report_default = {
5777
- type: "Profit_And_Loss",
5778
- business_id: "",
5779
- start_date: "",
5780
- end_date: "",
5781
- income: {
5782
- name: "INCOME",
5783
- display_name: "Income",
5784
- value: NaN,
5785
- line_items: null
5786
- },
5787
- cost_of_goods_sold: {
5788
- display_name: "Cost of Goods Sold",
5789
- name: "COGS",
5790
- value: NaN,
5791
- line_items: null
5792
- },
5793
- gross_profit: NaN,
5794
- expenses: {
5795
- name: "EXPENSES",
5796
- display_name: "Expenses",
5797
- value: NaN,
5798
- line_items: null
5799
- },
5800
- profit_before_taxes: NaN,
5801
- taxes: {
5802
- name: "TAXES",
5803
- display_name: "Taxes",
5804
- value: NaN,
5805
- line_items: null
5806
- },
5807
- net_profit: NaN,
5808
- other_outflows: {
5809
- name: "OTHER_OUTFLOWS",
5810
- display_name: "Other outflows",
5811
- value: NaN,
5812
- line_items: null
5813
- },
5814
- personal_expenses: {
5815
- name: "PERSONAL",
5816
- display_name: "Personal expenses",
5817
- value: NaN,
5818
- line_items: null
5819
- },
5820
- fully_categorized: false
6156
+ // src/components/ProfitAndLossDetailedCharts/Filters.tsx
6157
+ import React72 from "react";
6158
+ import Select3, { components as components3 } from "react-select";
6159
+ var Filters = ({
6160
+ filteredData,
6161
+ sidebarScope,
6162
+ filters,
6163
+ setFilterTypes
6164
+ }) => {
6165
+ return /* @__PURE__ */ React72.createElement("div", { className: "filters" }, /* @__PURE__ */ React72.createElement(Text, { size: "sm" /* sm */, className: "Layer__label" }, "Filters"), /* @__PURE__ */ React72.createElement(
6166
+ Select3,
6167
+ {
6168
+ className: "Layer__select type-select",
6169
+ classNamePrefix: "Layer__select",
6170
+ value: sidebarScope && filters[sidebarScope]?.types ? sidebarScope && filters[sidebarScope]?.types?.map((x) => ({
6171
+ value: x,
6172
+ label: x
6173
+ })) : [],
6174
+ isMulti: true,
6175
+ isClearable: false,
6176
+ options: [...new Set(filteredData?.map((x) => x.type))].map((x) => ({
6177
+ label: x,
6178
+ value: x
6179
+ })),
6180
+ onChange: (selected) => {
6181
+ setFilterTypes(
6182
+ sidebarScope ?? "expenses",
6183
+ selected.map((x) => x.value)
6184
+ );
6185
+ },
6186
+ components: {
6187
+ DropdownIndicator: (props) => /* @__PURE__ */ React72.createElement(components3.DropdownIndicator, { ...props }, /* @__PURE__ */ React72.createElement(ChevronDown_default, null)),
6188
+ Placeholder: (props) => /* @__PURE__ */ React72.createElement(components3.Placeholder, { ...props }, /* @__PURE__ */ React72.createElement("div", { className: "Layer__select__multi-all-placeholder-badge" }, "All"))
6189
+ }
6190
+ }
6191
+ ));
5821
6192
  };
5822
6193
 
5823
- // src/components/ProfitAndLossTable/ProfitAndLossTable.tsx
5824
- var ProfitAndLossTable = ({ lockExpanded }) => {
6194
+ // src/components/ProfitAndLossDetailedCharts/ProfitAndLossDetailedCharts.tsx
6195
+ import { format as format6 } from "date-fns";
6196
+ var ProfitAndLossDetailedCharts = ({
6197
+ scope,
6198
+ hideClose = false,
6199
+ showDatePicker = false
6200
+ }) => {
5825
6201
  const {
5826
- data: actualData,
6202
+ filteredDataRevenue,
6203
+ filteredTotalRevenue,
6204
+ filteredDataExpenses,
6205
+ filteredTotalExpenses,
6206
+ sortBy,
5827
6207
  isLoading,
5828
- setSidebarScope
5829
- } = useContext5(ProfitAndLoss.Context);
5830
- const data = !actualData || isLoading ? empty_profit_and_loss_report_default : actualData;
5831
- if (isLoading || actualData === void 0) {
5832
- return /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-table__loader-container" }, /* @__PURE__ */ React73.createElement(Loader2, null));
5833
- }
5834
- return /* @__PURE__ */ React73.createElement(React73.Fragment, null, /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-table Layer__profit-and-loss-table--main" }, /* @__PURE__ */ React73.createElement(
5835
- ProfitAndLossRow,
5836
- {
5837
- lineItem: data.income,
5838
- direction: "CREDIT" /* CREDIT */,
5839
- lockExpanded,
5840
- scope: "revenue",
5841
- setSidebarScope
5842
- }
5843
- ), /* @__PURE__ */ React73.createElement(
5844
- ProfitAndLossRow,
5845
- {
5846
- lineItem: data.cost_of_goods_sold,
5847
- direction: "DEBIT" /* DEBIT */,
5848
- lockExpanded,
5849
- scope: "expenses",
5850
- setSidebarScope
5851
- }
5852
- ), /* @__PURE__ */ React73.createElement(
5853
- ProfitAndLossRow,
5854
- {
5855
- lineItem: {
5856
- value: data.gross_profit,
5857
- display_name: "Gross Profit"
5858
- },
5859
- variant: "summation",
5860
- direction: "CREDIT" /* CREDIT */,
5861
- lockExpanded,
5862
- scope: "revenue",
5863
- setSidebarScope
5864
- }
5865
- ), /* @__PURE__ */ React73.createElement(
5866
- ProfitAndLossRow,
5867
- {
5868
- lineItem: data.expenses,
5869
- direction: "DEBIT" /* DEBIT */,
5870
- lockExpanded,
5871
- scope: "expenses",
5872
- setSidebarScope
5873
- }
5874
- ), /* @__PURE__ */ React73.createElement(
5875
- ProfitAndLossRow,
5876
- {
5877
- lineItem: {
5878
- value: data.profit_before_taxes,
5879
- display_name: "Profit Before Taxes"
5880
- },
5881
- variant: "summation",
5882
- direction: "CREDIT" /* CREDIT */,
5883
- lockExpanded,
5884
- scope: "revenue",
5885
- setSidebarScope
5886
- }
5887
- ), /* @__PURE__ */ React73.createElement(
5888
- ProfitAndLossRow,
6208
+ filters,
6209
+ dateRange,
6210
+ sidebarScope,
6211
+ setSidebarScope,
6212
+ setFilterTypes
6213
+ } = useContext4(ProfitAndLoss.Context);
6214
+ const theScope = scope ? scope : sidebarScope;
6215
+ const data = theScope === "revenue" ? filteredDataRevenue : filteredDataExpenses;
6216
+ const total = theScope === "revenue" ? filteredTotalRevenue : filteredTotalExpenses;
6217
+ const [hoveredItem, setHoveredItem] = useState16();
6218
+ return /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-detailed-charts" }, /* @__PURE__ */ React73.createElement("header", { className: "Layer__profit-and-loss-detailed-charts__header" }, /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-detailed-charts__head" }, /* @__PURE__ */ React73.createElement(Text, { size: "lg" /* lg */, weight: "bold" /* bold */, className: "title" }, humanizeTitle(theScope)), /* @__PURE__ */ React73.createElement(Text, { size: "sm" /* sm */, className: "date" }, format6(dateRange.startDate, "LLLL, y")), showDatePicker && /* @__PURE__ */ React73.createElement(ProfitAndLossDatePicker, null)), !hideClose && /* @__PURE__ */ React73.createElement(
6219
+ Button,
5889
6220
  {
5890
- lineItem: data.taxes,
5891
- direction: "DEBIT" /* DEBIT */,
5892
- lockExpanded,
5893
- scope: "expenses",
5894
- setSidebarScope
6221
+ rightIcon: /* @__PURE__ */ React73.createElement(X_default, null),
6222
+ iconOnly: true,
6223
+ onClick: () => setSidebarScope(void 0),
6224
+ variant: "secondary" /* secondary */
5895
6225
  }
5896
- ), /* @__PURE__ */ React73.createElement(
5897
- ProfitAndLossRow,
6226
+ )), /* @__PURE__ */ React73.createElement("header", { className: "Layer__profit-and-loss-detailed-charts__header--tablet" }, /* @__PURE__ */ React73.createElement(BackButton, { onClick: () => setSidebarScope(void 0) })), /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-detailed-charts__content" }, /* @__PURE__ */ React73.createElement(
6227
+ DetailedChart,
5898
6228
  {
5899
- lineItem: {
5900
- value: data.net_profit,
5901
- display_name: "Net Profit"
5902
- },
5903
- variant: "summation",
5904
- direction: "CREDIT" /* CREDIT */,
5905
- lockExpanded
6229
+ filteredData: data,
6230
+ filteredTotal: total,
6231
+ hoveredItem,
6232
+ setHoveredItem,
6233
+ sidebarScope: theScope,
6234
+ date: dateRange.startDate,
6235
+ isLoading
5906
6236
  }
5907
- )), data.other_outflows || data.personal_expenses ? /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-table Layer__profit-and-loss-table__outflows" }, /* @__PURE__ */ React73.createElement(
5908
- ProfitAndLossRow,
6237
+ ), /* @__PURE__ */ React73.createElement("div", { className: "Layer__profit-and-loss-detailed-charts__table-wrapper" }, /* @__PURE__ */ React73.createElement(
6238
+ Filters,
5909
6239
  {
5910
- lineItem: data.other_outflows,
5911
- direction: "DEBIT" /* DEBIT */,
5912
- lockExpanded
6240
+ filteredData: data,
6241
+ sidebarScope: theScope,
6242
+ filters,
6243
+ setFilterTypes
5913
6244
  }
5914
6245
  ), /* @__PURE__ */ React73.createElement(
5915
- ProfitAndLossRow,
6246
+ DetailedTable,
5916
6247
  {
5917
- lineItem: data.personal_expenses,
5918
- direction: "DEBIT" /* DEBIT */,
5919
- lockExpanded
6248
+ filteredData: data,
6249
+ sidebarScope: theScope,
6250
+ filters,
6251
+ sortBy,
6252
+ hoveredItem,
6253
+ setHoveredItem
5920
6254
  }
5921
- )) : null);
6255
+ ))));
5922
6256
  };
5923
6257
 
5924
- // src/components/ProfitAndLoss/ProfitAndLoss.tsx
5925
- import { endOfMonth as endOfMonth4, startOfMonth as startOfMonth4 } from "date-fns";
5926
- var PNLContext = createContext2({
5927
- data: void 0,
5928
- filteredData: [],
5929
- filteredTotal: void 0,
5930
- isLoading: true,
5931
- isValidating: false,
5932
- error: void 0,
5933
- dateRange: {
5934
- startDate: startOfMonth4(/* @__PURE__ */ new Date()),
5935
- endDate: endOfMonth4(/* @__PURE__ */ new Date())
5936
- },
5937
- changeDateRange: () => {
5938
- },
5939
- refetch: () => {
5940
- },
5941
- sidebarScope: void 0,
5942
- setSidebarScope: () => {
5943
- },
5944
- sortBy: () => {
5945
- },
5946
- setFilterTypes: () => {
5947
- },
5948
- filters: {
5949
- expenses: void 0,
5950
- revenue: void 0
6258
+ // src/components/ProfitAndLossSummaries/ProfitAndLossSummaries.tsx
6259
+ import React76, { useContext as useContext5, useMemo as useMemo6 } from "react";
6260
+
6261
+ // src/components/SkeletonLoader/SkeletonLoader.tsx
6262
+ import React74 from "react";
6263
+ import classNames26 from "classnames";
6264
+ var SkeletonLoader = ({
6265
+ height,
6266
+ width,
6267
+ className
6268
+ }) => {
6269
+ const baseClassName = classNames26(
6270
+ "Layer__skeleton-loader Layer__anim--skeleton-loading",
6271
+ className
6272
+ );
6273
+ return /* @__PURE__ */ React74.createElement("div", { className: baseClassName, style: { width, height } });
6274
+ };
6275
+
6276
+ // src/components/ProfitAndLossSummaries/MiniChart.tsx
6277
+ import React75 from "react";
6278
+ import { PieChart as PieChart2, Pie as Pie2, Cell as Cell3 } from "recharts";
6279
+ var MiniChart = ({ data }) => {
6280
+ return /* @__PURE__ */ React75.createElement(PieChart2, { width: 48, height: 48, className: "mini-chart" }, /* @__PURE__ */ React75.createElement(
6281
+ Pie2,
6282
+ {
6283
+ data,
6284
+ dataKey: "value",
6285
+ nameKey: "name",
6286
+ cx: "50%",
6287
+ cy: "50%",
6288
+ innerRadius: 10,
6289
+ outerRadius: 16,
6290
+ paddingAngle: 0.2,
6291
+ fill: "#8884d8",
6292
+ width: 24,
6293
+ height: 24,
6294
+ animationDuration: 250,
6295
+ animationEasing: "ease-in-out"
6296
+ },
6297
+ data.map((entry, index) => {
6298
+ const colorConfig = DEFAULT_CHART_COLORS[index % DEFAULT_CHART_COLORS.length];
6299
+ return /* @__PURE__ */ React75.createElement(
6300
+ Cell3,
6301
+ {
6302
+ key: `cell-${index}`,
6303
+ className: `Layer__profit-and-loss-detailed-charts__pie`,
6304
+ fill: entry.name === "placeholder" ? "#e6e6e6" : colorConfig.color,
6305
+ opacity: colorConfig.opacity
6306
+ }
6307
+ );
6308
+ })
6309
+ ));
6310
+ };
6311
+
6312
+ // src/components/ProfitAndLossSummaries/ProfitAndLossSummaries.tsx
6313
+ import classNames27 from "classnames";
6314
+ var CHART_PLACEHOLDER = [
6315
+ {
6316
+ name: "placeholder",
6317
+ display_name: "placeholder",
6318
+ value: 1,
6319
+ type: "placeholder",
6320
+ share: 1
5951
6321
  }
5952
- });
5953
- var ProfitAndLoss = ({ children, tagFilter, reportingBasis }) => {
5954
- const contextData = useProfitAndLoss({ tagFilter, reportingBasis });
5955
- return /* @__PURE__ */ React74.createElement(PNLContext.Provider, { value: contextData }, /* @__PURE__ */ React74.createElement("div", { className: "Layer__component Layer__profit-and-loss" }, children));
6322
+ ];
6323
+ var buildMiniChartData = (scope, data) => {
6324
+ if (!data) {
6325
+ return CHART_PLACEHOLDER;
6326
+ }
6327
+ let items = [];
6328
+ switch (scope) {
6329
+ case "revenue":
6330
+ items = collectRevenueItems(data);
6331
+ break;
6332
+ default:
6333
+ items = collectExpensesItems(data);
6334
+ }
6335
+ if (!items || items.length === 0 || !items.find((x) => Math.abs(x.value) !== 0)) {
6336
+ return CHART_PLACEHOLDER;
6337
+ }
6338
+ return items.slice();
6339
+ };
6340
+ var ProfitAndLossSummaries = ({
6341
+ vertical,
6342
+ revenueLabel = "Revenue",
6343
+ actionable = true
6344
+ }) => {
6345
+ const {
6346
+ data: storedData,
6347
+ isLoading,
6348
+ setSidebarScope,
6349
+ sidebarScope
6350
+ } = useContext5(ProfitAndLoss.Context);
6351
+ const expensesChartData = useMemo6(() => {
6352
+ return buildMiniChartData("expenses", storedData);
6353
+ }, [storedData]);
6354
+ const revenueChartData = useMemo6(() => {
6355
+ return buildMiniChartData("revenue", storedData);
6356
+ }, [storedData]);
6357
+ const data = storedData ? storedData : { income: { value: NaN }, net_profit: NaN };
6358
+ const incomeDirectionClass = (data.income.value ?? NaN) < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--positive";
6359
+ const expensesDirectionClass = (data?.income?.value ?? NaN) - data.net_profit < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--positive";
6360
+ const netProfitDirectionClass = data.net_profit < 0 ? "Layer__profit-and-loss-summaries__amount--negative" : "Layer__profit-and-loss-summaries__amount--positive";
6361
+ return /* @__PURE__ */ React76.createElement(
6362
+ "div",
6363
+ {
6364
+ className: `Layer__profit-and-loss-summaries ${vertical ? "flex-col" : ""}`
6365
+ },
6366
+ /* @__PURE__ */ React76.createElement(
6367
+ "div",
6368
+ {
6369
+ className: classNames27(
6370
+ "Layer__profit-and-loss-summaries__summary",
6371
+ actionable && "Layer__actionable",
6372
+ "Layer__profit-and-loss-summaries__summary--income",
6373
+ sidebarScope === "revenue" ? "active" : ""
6374
+ ),
6375
+ onClick: () => {
6376
+ actionable && setSidebarScope("revenue");
6377
+ }
6378
+ },
6379
+ /* @__PURE__ */ React76.createElement(MiniChart, { data: revenueChartData }),
6380
+ /* @__PURE__ */ React76.createElement("div", { className: "Layer__profit-and-loss-summaries__text" }, /* @__PURE__ */ React76.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, revenueLabel), isLoading || storedData === void 0 ? /* @__PURE__ */ React76.createElement("div", { className: "Layer__profit-and-loss-summaries__loader" }, /* @__PURE__ */ React76.createElement(SkeletonLoader, null)) : /* @__PURE__ */ React76.createElement(
6381
+ "span",
6382
+ {
6383
+ className: `Layer__profit-and-loss-summaries__amount ${incomeDirectionClass}`
6384
+ },
6385
+ centsToDollars(Math.abs(data?.income?.value ?? NaN))
6386
+ ))
6387
+ ),
6388
+ /* @__PURE__ */ React76.createElement(
6389
+ "div",
6390
+ {
6391
+ className: classNames27(
6392
+ "Layer__profit-and-loss-summaries__summary",
6393
+ actionable && "Layer__actionable",
6394
+ "Layer__profit-and-loss-summaries__summary--expenses",
6395
+ sidebarScope === "expenses" ? "active" : ""
6396
+ ),
6397
+ onClick: () => {
6398
+ actionable && setSidebarScope("expenses");
6399
+ }
6400
+ },
6401
+ /* @__PURE__ */ React76.createElement(MiniChart, { data: expensesChartData }),
6402
+ /* @__PURE__ */ React76.createElement("div", { className: "Layer__profit-and-loss-summaries__text" }, /* @__PURE__ */ React76.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Expenses"), isLoading || storedData === void 0 ? /* @__PURE__ */ React76.createElement("div", { className: "Layer__profit-and-loss-summaries__loader" }, /* @__PURE__ */ React76.createElement(SkeletonLoader, { className: "Layer__profit-and-loss-summaries__loader" })) : /* @__PURE__ */ React76.createElement(
6403
+ "span",
6404
+ {
6405
+ className: `Layer__profit-and-loss-summaries__amount ${expensesDirectionClass}`
6406
+ },
6407
+ centsToDollars(
6408
+ Math.abs((data.income.value ?? 0) - data.net_profit)
6409
+ )
6410
+ ))
6411
+ ),
6412
+ /* @__PURE__ */ React76.createElement(
6413
+ "div",
6414
+ {
6415
+ className: classNames27(
6416
+ "Layer__profit-and-loss-summaries__summary net-profit Layer__profit-and-loss-summaries__summary--net-profit",
6417
+ actionable && "Layer__actionable"
6418
+ )
6419
+ },
6420
+ /* @__PURE__ */ React76.createElement("div", { className: "Layer__profit-and-loss-summaries__text" }, /* @__PURE__ */ React76.createElement("span", { className: "Layer__profit-and-loss-summaries__title" }, "Net Profit"), isLoading || storedData === void 0 ? /* @__PURE__ */ React76.createElement("div", { className: "Layer__profit-and-loss-summaries__loader" }, /* @__PURE__ */ React76.createElement(SkeletonLoader, { className: "Layer__profit-and-loss-summaries__loader" })) : /* @__PURE__ */ React76.createElement(
6421
+ "span",
6422
+ {
6423
+ className: `Layer__profit-and-loss-summaries__amount ${netProfitDirectionClass}`
6424
+ },
6425
+ centsToDollars(Math.abs(data.net_profit))
6426
+ ))
6427
+ )
6428
+ );
5956
6429
  };
5957
- ProfitAndLoss.Chart = ProfitAndLossChart;
5958
- ProfitAndLoss.Context = PNLContext;
5959
- ProfitAndLoss.DatePicker = ProfitAndLossDatePicker;
5960
- ProfitAndLoss.Summaries = ProfitAndLossSummaries;
5961
- ProfitAndLoss.Table = ProfitAndLossTable;
5962
6430
 
5963
- // src/components/ProfitAndLossView/ProfitAndLossView.tsx
5964
- import React81, { useContext as useContext7 } from "react";
6431
+ // src/components/ProfitAndLossTable/ProfitAndLossTable.tsx
6432
+ import React79, { useContext as useContext6 } from "react";
5965
6433
 
5966
- // src/components/ProfitAndLossDetailedCharts/ProfitAndLossDetailedCharts.tsx
5967
- import React80, { useContext as useContext6, useState as useState16 } from "react";
6434
+ // src/components/ProfitAndLossRow/ProfitAndLossRow.tsx
6435
+ import React78, { useState as useState17 } from "react";
5968
6436
 
5969
- // src/icons/X.tsx
5970
- import * as React75 from "react";
5971
- var X = ({ size = 18, ...props }) => /* @__PURE__ */ React75.createElement(
6437
+ // src/icons/PieChart.tsx
6438
+ import * as React77 from "react";
6439
+ var PieChart3 = ({ size = 12, ...props }) => /* @__PURE__ */ React77.createElement(
5972
6440
  "svg",
5973
6441
  {
5974
6442
  xmlns: "http://www.w3.org/2000/svg",
5975
- viewBox: "0 0 18 18",
6443
+ viewBox: "0 0 12 12",
5976
6444
  fill: "none",
5977
6445
  ...props,
5978
6446
  width: size,
5979
6447
  height: size
5980
6448
  },
5981
- /* @__PURE__ */ React75.createElement(
6449
+ /* @__PURE__ */ React77.createElement("g", null, /* @__PURE__ */ React77.createElement(
5982
6450
  "path",
5983
6451
  {
5984
- d: "M13.5 4.5L4.5 13.5",
6452
+ d: "M10.2213 7.78271C9.92969 8.47226 9.47363 9.07989 8.89297 9.55247C8.3123 10.0251 7.62471 10.3482 6.89031 10.4936C6.1559 10.6391 5.39705 10.6024 4.68009 10.3869C3.96313 10.1713 3.30989 9.78337 2.77749 9.25701C2.24509 8.73065 1.84973 8.08189 1.62598 7.36744C1.40223 6.65298 1.3569 5.8946 1.49396 5.15858C1.63102 4.42257 1.94629 3.73133 2.41221 3.14531C2.87813 2.55928 3.48051 2.09631 4.16669 1.79688",
5985
6453
  stroke: "currentColor",
5986
6454
  strokeLinecap: "round",
5987
6455
  strokeLinejoin: "round"
5988
6456
  }
5989
- ),
5990
- /* @__PURE__ */ React75.createElement(
6457
+ ), /* @__PURE__ */ React77.createElement(
5991
6458
  "path",
5992
6459
  {
5993
- d: "M4.5 4.5L13.5 13.5",
6460
+ d: "M10.5833 6.00033C10.5833 5.39843 10.4648 4.80244 10.2344 4.24636C10.0041 3.69028 9.66651 3.18502 9.24091 2.75942C8.8153 2.33382 8.31004 1.99621 7.75397 1.76588C7.19789 1.53554 6.60189 1.41699 6 1.41699V6.00033H10.5833Z",
5994
6461
  stroke: "currentColor",
5995
6462
  strokeLinecap: "round",
5996
6463
  strokeLinejoin: "round"
5997
6464
  }
5998
- )
6465
+ ))
5999
6466
  );
6000
- var X_default = X;
6467
+ var PieChart_default = PieChart3;
6001
6468
 
6002
- // src/components/ProfitAndLossDetailedCharts/DetailedChart.tsx
6003
- import React76, { useMemo as useMemo6 } from "react";
6004
- import {
6005
- PieChart as PieChart3,
6006
- Pie as Pie2,
6007
- Cell as Cell3,
6008
- ResponsiveContainer as ResponsiveContainer2,
6009
- Label,
6010
- Text as ChartText
6011
- } from "recharts";
6012
- var DetailedChart = ({
6013
- filteredData,
6014
- filteredTotal,
6015
- hoveredItem,
6016
- setHoveredItem,
6017
- sidebarScope,
6018
- date
6469
+ // src/components/ProfitAndLossRow/ProfitAndLossRow.tsx
6470
+ var ProfitAndLossRow = ({
6471
+ variant,
6472
+ lineItem,
6473
+ depth = 0,
6474
+ maxDepth = 1,
6475
+ direction = "DEBIT" /* DEBIT */,
6476
+ lockExpanded = false,
6477
+ scope,
6478
+ setSidebarScope
6019
6479
  }) => {
6020
- const chartData = useMemo6(() => {
6021
- if (!filteredData) {
6022
- return [];
6023
- }
6024
- return filteredData.map((x) => {
6025
- if (x.hidden) {
6026
- return {
6027
- name: x.display_name,
6028
- value: 0
6029
- };
6030
- }
6031
- return {
6032
- name: x.display_name,
6033
- value: x.value
6034
- };
6035
- });
6036
- }, [filteredData]);
6037
- return /* @__PURE__ */ React76.createElement("div", { className: "chart-field" }, /* @__PURE__ */ React76.createElement("div", { className: "header--tablet" }, /* @__PURE__ */ React76.createElement(Text, { size: "lg" /* lg */, weight: "bold" /* bold */, className: "title" }, humanizeTitle(sidebarScope)), /* @__PURE__ */ React76.createElement(ProfitAndLossDatePicker, null)), /* @__PURE__ */ React76.createElement("div", { className: "chart-container" }, /* @__PURE__ */ React76.createElement(ResponsiveContainer2, null, /* @__PURE__ */ React76.createElement(PieChart3, null, /* @__PURE__ */ React76.createElement(
6038
- Pie2,
6039
- {
6040
- data: chartData,
6041
- dataKey: "value",
6042
- nameKey: "name",
6043
- cx: "50%",
6044
- cy: "50%",
6045
- innerRadius: 105,
6046
- outerRadius: 120,
6047
- paddingAngle: 0.5,
6048
- fill: "#8884d8",
6049
- animationDuration: 200,
6050
- animationEasing: "ease-in-out"
6051
- },
6052
- chartData.map((entry, index) => {
6053
- const colorConfig = DEFAULT_CHART_COLORS[index % DEFAULT_CHART_COLORS.length];
6054
- let fill = colorConfig.color;
6055
- let opacity = colorConfig.opacity;
6056
- let active = true;
6057
- if (hoveredItem && entry.name !== hoveredItem) {
6058
- active = false;
6059
- fill = void 0;
6060
- opacity = INACTIVE_OPACITY_LEVELS[index % INACTIVE_OPACITY_LEVELS.length];
6061
- }
6062
- return /* @__PURE__ */ React76.createElement(
6063
- Cell3,
6064
- {
6065
- key: `cell-${index}`,
6066
- className: `Layer__profit-and-loss-detailed-charts__pie ${hoveredItem && active ? "active" : "inactive"}`,
6067
- style: { fill },
6068
- opacity,
6069
- onMouseEnter: () => setHoveredItem(entry.name),
6070
- onMouseLeave: () => setHoveredItem(void 0)
6071
- }
6072
- );
6073
- }),
6074
- /* @__PURE__ */ React76.createElement(
6075
- Label,
6480
+ if (!lineItem) {
6481
+ return null;
6482
+ }
6483
+ const { value, display_name, line_items } = lineItem;
6484
+ const [expanded, setExpanded] = useState17(true);
6485
+ const amount = value ?? 0;
6486
+ const amountString = centsToDollars(Math.abs(amount));
6487
+ const labelClasses = [
6488
+ "Layer__profit-and-loss-row",
6489
+ "Layer__profit-and-loss-row__label"
6490
+ ];
6491
+ const valueClasses = [
6492
+ "Layer__profit-and-loss-row",
6493
+ "Layer__profit-and-loss-row__value"
6494
+ ];
6495
+ const positive = amount === 0 || direction === "CREDIT" /* CREDIT */ && amount > 0 || direction === "DEBIT" /* DEBIT */ && amount < 0;
6496
+ valueClasses.push(
6497
+ positive ? "Layer__profit-and-loss-row__value--amount-positive" : "Layer__profit-and-loss-row__value--amount-negative"
6498
+ );
6499
+ labelClasses.push(`Layer__profit-and-loss-row__label--depth-${depth}`);
6500
+ valueClasses.push(`Layer__profit-and-loss-row__value--depth-${depth}`);
6501
+ variant && labelClasses.push(`Layer__profit-and-loss-row__label--variant-${variant}`);
6502
+ variant && valueClasses.push(`Layer__profit-and-loss-row__value--variant-${variant}`);
6503
+ const toggleExpanded = () => setExpanded(!expanded);
6504
+ const canGoDeeper = depth < maxDepth;
6505
+ const hasChildren = (line_items?.length ?? 0) > 0;
6506
+ const displayChildren = hasChildren && canGoDeeper;
6507
+ labelClasses.push(
6508
+ `Layer__profit-and-loss-row__label--display-children-${displayChildren}`
6509
+ );
6510
+ valueClasses.push(
6511
+ `Layer__profit-and-loss-row__value--display-children-${displayChildren}`
6512
+ );
6513
+ displayChildren && expanded && labelClasses.push("Layer__profit-and-loss-row__label--expanded");
6514
+ displayChildren && expanded && valueClasses.push("Layer__profit-and-loss-row__value--expanded");
6515
+ return /* @__PURE__ */ React78.createElement(React78.Fragment, null, /* @__PURE__ */ React78.createElement(
6516
+ "div",
6517
+ {
6518
+ className: labelClasses.join(" "),
6519
+ onClick: () => !lockExpanded && toggleExpanded()
6520
+ },
6521
+ /* @__PURE__ */ React78.createElement("span", { className: "Layer__profit-and-loss-row__label__title" }, !lockExpanded && variant !== "summation" ? /* @__PURE__ */ React78.createElement(
6522
+ ChevronDownFill_default,
6076
6523
  {
6077
- position: "center",
6078
- value: "Total",
6079
- className: "pie-center-label-title",
6080
- content: (props) => {
6081
- const { cx, cy } = props.viewBox ?? {
6082
- cx: 0,
6083
- cy: 0
6084
- };
6085
- const positioningProps = {
6086
- x: cx,
6087
- y: (cy || 0) - 15,
6088
- textAnchor: "middle",
6089
- verticalAnchor: "middle"
6090
- };
6091
- let text = "Total";
6092
- if (hoveredItem) {
6093
- text = hoveredItem;
6094
- }
6095
- return /* @__PURE__ */ React76.createElement(
6096
- ChartText,
6097
- {
6098
- ...positioningProps,
6099
- className: "pie-center-label__title"
6100
- },
6101
- text
6102
- );
6524
+ size: 16,
6525
+ className: "Layer__profit-and-loss-row__label__chevron"
6526
+ }
6527
+ ) : null, /* @__PURE__ */ React78.createElement(Text, null, display_name)),
6528
+ setSidebarScope && /* @__PURE__ */ React78.createElement(
6529
+ "span",
6530
+ {
6531
+ className: "Layer__profit-and-loss-row__detailed-chart-btn",
6532
+ onClick: (e) => {
6533
+ e.stopPropagation();
6534
+ setSidebarScope && setSidebarScope(scope ?? "expenses");
6103
6535
  }
6536
+ },
6537
+ /* @__PURE__ */ React78.createElement(PieChart_default, null)
6538
+ )
6539
+ ), /* @__PURE__ */ React78.createElement("div", { className: valueClasses.join(" ") }, /* @__PURE__ */ React78.createElement(Text, null, amountString)), canGoDeeper && hasChildren && /* @__PURE__ */ React78.createElement(
6540
+ "div",
6541
+ {
6542
+ className: `Layer__profit-and-loss-row__children ${expanded && "Layer__profit-and-loss-row__children--expanded"}`
6543
+ },
6544
+ /* @__PURE__ */ React78.createElement("div", { className: "Layer__profit-and-loss-row__children--content" }, (line_items || []).map((line_item) => /* @__PURE__ */ React78.createElement(
6545
+ ProfitAndLossRow,
6546
+ {
6547
+ key: line_item.display_name,
6548
+ lineItem: line_item,
6549
+ depth: depth + 1,
6550
+ maxDepth,
6551
+ direction
6552
+ }
6553
+ )))
6554
+ ));
6555
+ };
6556
+
6557
+ // src/components/ProfitAndLossTable/empty_profit_and_loss_report.ts
6558
+ var empty_profit_and_loss_report_default = {
6559
+ type: "Profit_And_Loss",
6560
+ business_id: "",
6561
+ start_date: "",
6562
+ end_date: "",
6563
+ income: {
6564
+ name: "INCOME",
6565
+ display_name: "Income",
6566
+ value: NaN,
6567
+ line_items: null
6568
+ },
6569
+ cost_of_goods_sold: {
6570
+ display_name: "Cost of Goods Sold",
6571
+ name: "COGS",
6572
+ value: NaN,
6573
+ line_items: null
6574
+ },
6575
+ gross_profit: NaN,
6576
+ expenses: {
6577
+ name: "EXPENSES",
6578
+ display_name: "Expenses",
6579
+ value: NaN,
6580
+ line_items: null
6581
+ },
6582
+ profit_before_taxes: NaN,
6583
+ taxes: {
6584
+ name: "TAXES",
6585
+ display_name: "Taxes",
6586
+ value: NaN,
6587
+ line_items: null
6588
+ },
6589
+ net_profit: NaN,
6590
+ other_outflows: {
6591
+ name: "OTHER_OUTFLOWS",
6592
+ display_name: "Other outflows",
6593
+ value: NaN,
6594
+ line_items: null
6595
+ },
6596
+ personal_expenses: {
6597
+ name: "PERSONAL",
6598
+ display_name: "Personal expenses",
6599
+ value: NaN,
6600
+ line_items: null
6601
+ },
6602
+ fully_categorized: false
6603
+ };
6604
+
6605
+ // src/components/ProfitAndLossTable/ProfitAndLossTable.tsx
6606
+ import classNames28 from "classnames";
6607
+ var ProfitAndLossTable = ({ lockExpanded, asContainer }) => {
6608
+ const {
6609
+ data: actualData,
6610
+ isLoading,
6611
+ setSidebarScope
6612
+ } = useContext6(ProfitAndLoss.Context);
6613
+ const data = !actualData || isLoading ? empty_profit_and_loss_report_default : actualData;
6614
+ if (isLoading || actualData === void 0) {
6615
+ return /* @__PURE__ */ React79.createElement(
6616
+ "div",
6617
+ {
6618
+ className: classNames28(
6619
+ "Layer__profit-and-loss-table__loader-container",
6620
+ asContainer && "Layer__component-container"
6621
+ )
6622
+ },
6623
+ /* @__PURE__ */ React79.createElement(Loader2, null)
6624
+ );
6625
+ }
6626
+ return /* @__PURE__ */ React79.createElement(React79.Fragment, null, /* @__PURE__ */ React79.createElement(
6627
+ "div",
6628
+ {
6629
+ className: classNames28(
6630
+ "Layer__profit-and-loss-table Layer__profit-and-loss-table--main",
6631
+ asContainer && "Layer__component-container"
6632
+ )
6633
+ },
6634
+ /* @__PURE__ */ React79.createElement(
6635
+ ProfitAndLossRow,
6636
+ {
6637
+ lineItem: data.income,
6638
+ direction: "CREDIT" /* CREDIT */,
6639
+ lockExpanded,
6640
+ scope: "revenue",
6641
+ setSidebarScope
6104
6642
  }
6105
6643
  ),
6106
- /* @__PURE__ */ React76.createElement(
6107
- Label,
6644
+ /* @__PURE__ */ React79.createElement(
6645
+ ProfitAndLossRow,
6108
6646
  {
6109
- position: "center",
6110
- value: "Total",
6111
- className: "pie-center-label-title",
6112
- content: (props) => {
6113
- const { cx, cy } = props.viewBox ?? {
6114
- cx: 0,
6115
- cy: 0
6116
- };
6117
- const positioningProps = {
6118
- x: cx,
6119
- y: (cy || 0) + 5,
6120
- textAnchor: "middle",
6121
- verticalAnchor: "middle"
6122
- };
6123
- let value = filteredTotal;
6124
- if (hoveredItem) {
6125
- value = filteredData.find(
6126
- (x) => x.display_name === hoveredItem
6127
- )?.value;
6128
- }
6129
- return /* @__PURE__ */ React76.createElement(
6130
- ChartText,
6131
- {
6132
- ...positioningProps,
6133
- className: "pie-center-label__value"
6134
- },
6135
- `$${centsToDollars(value)}`
6136
- );
6137
- }
6647
+ lineItem: data.cost_of_goods_sold,
6648
+ direction: "DEBIT" /* DEBIT */,
6649
+ lockExpanded,
6650
+ scope: "expenses",
6651
+ setSidebarScope
6138
6652
  }
6139
6653
  ),
6140
- /* @__PURE__ */ React76.createElement(
6141
- Label,
6654
+ /* @__PURE__ */ React79.createElement(
6655
+ ProfitAndLossRow,
6142
6656
  {
6143
- position: "center",
6144
- value: "Total",
6145
- className: "pie-center-label-title",
6146
- content: (props) => {
6147
- const { cx, cy } = props.viewBox ?? {
6148
- cx: 0,
6149
- cy: 0
6150
- };
6151
- const positioningProps = {
6152
- x: cx,
6153
- y: (cy || 0) + 25,
6154
- height: 20,
6155
- textAnchor: "middle",
6156
- verticalAnchor: "middle"
6157
- };
6158
- if (hoveredItem) {
6159
- return /* @__PURE__ */ React76.createElement(
6160
- ChartText,
6161
- {
6162
- ...positioningProps,
6163
- className: "pie-center-label__share"
6164
- },
6165
- `${formatPercent(
6166
- filteredData.find((x) => x.display_name === hoveredItem)?.share
6167
- )}%`
6168
- );
6169
- }
6170
- return;
6171
- }
6657
+ lineItem: {
6658
+ value: data.gross_profit,
6659
+ display_name: "Gross Profit"
6660
+ },
6661
+ variant: "summation",
6662
+ direction: "CREDIT" /* CREDIT */,
6663
+ lockExpanded,
6664
+ scope: "revenue",
6665
+ setSidebarScope
6666
+ }
6667
+ ),
6668
+ /* @__PURE__ */ React79.createElement(
6669
+ ProfitAndLossRow,
6670
+ {
6671
+ lineItem: data.expenses,
6672
+ direction: "DEBIT" /* DEBIT */,
6673
+ lockExpanded,
6674
+ scope: "expenses",
6675
+ setSidebarScope
6676
+ }
6677
+ ),
6678
+ /* @__PURE__ */ React79.createElement(
6679
+ ProfitAndLossRow,
6680
+ {
6681
+ lineItem: {
6682
+ value: data.profit_before_taxes,
6683
+ display_name: "Profit Before Taxes"
6684
+ },
6685
+ variant: "summation",
6686
+ direction: "CREDIT" /* CREDIT */,
6687
+ lockExpanded,
6688
+ scope: "revenue",
6689
+ setSidebarScope
6690
+ }
6691
+ ),
6692
+ /* @__PURE__ */ React79.createElement(
6693
+ ProfitAndLossRow,
6694
+ {
6695
+ lineItem: data.taxes,
6696
+ direction: "DEBIT" /* DEBIT */,
6697
+ lockExpanded,
6698
+ scope: "expenses",
6699
+ setSidebarScope
6700
+ }
6701
+ ),
6702
+ /* @__PURE__ */ React79.createElement(
6703
+ ProfitAndLossRow,
6704
+ {
6705
+ lineItem: {
6706
+ value: data.net_profit,
6707
+ display_name: "Net Profit"
6708
+ },
6709
+ variant: "summation",
6710
+ direction: "CREDIT" /* CREDIT */,
6711
+ lockExpanded
6172
6712
  }
6173
6713
  )
6174
- )))));
6714
+ ), data.other_outflows || data.personal_expenses ? /* @__PURE__ */ React79.createElement("div", { className: "Layer__profit-and-loss-table Layer__profit-and-loss-table__outflows" }, /* @__PURE__ */ React79.createElement(
6715
+ ProfitAndLossRow,
6716
+ {
6717
+ lineItem: data.other_outflows,
6718
+ direction: "DEBIT" /* DEBIT */,
6719
+ lockExpanded
6720
+ }
6721
+ ), /* @__PURE__ */ React79.createElement(
6722
+ ProfitAndLossRow,
6723
+ {
6724
+ lineItem: data.personal_expenses,
6725
+ direction: "DEBIT" /* DEBIT */,
6726
+ lockExpanded
6727
+ }
6728
+ )) : null);
6729
+ };
6730
+
6731
+ // src/components/ProfitAndLoss/ProfitAndLoss.tsx
6732
+ import { endOfMonth as endOfMonth4, startOfMonth as startOfMonth4 } from "date-fns";
6733
+ var PNLContext = createContext2({
6734
+ data: void 0,
6735
+ filteredDataRevenue: [],
6736
+ filteredTotalRevenue: void 0,
6737
+ filteredDataExpenses: [],
6738
+ filteredTotalExpenses: void 0,
6739
+ isLoading: true,
6740
+ isValidating: false,
6741
+ error: void 0,
6742
+ dateRange: {
6743
+ startDate: startOfMonth4(/* @__PURE__ */ new Date()),
6744
+ endDate: endOfMonth4(/* @__PURE__ */ new Date())
6745
+ },
6746
+ changeDateRange: () => {
6747
+ },
6748
+ refetch: () => {
6749
+ },
6750
+ sidebarScope: void 0,
6751
+ setSidebarScope: () => {
6752
+ },
6753
+ sortBy: () => {
6754
+ },
6755
+ setFilterTypes: () => {
6756
+ },
6757
+ filters: {
6758
+ expenses: void 0,
6759
+ revenue: void 0
6760
+ }
6761
+ });
6762
+ var ProfitAndLoss = ({
6763
+ children,
6764
+ tagFilter,
6765
+ reportingBasis,
6766
+ asContainer = true
6767
+ }) => {
6768
+ const contextData = useProfitAndLoss({ tagFilter, reportingBasis });
6769
+ return /* @__PURE__ */ React80.createElement(PNLContext.Provider, { value: contextData }, asContainer ? /* @__PURE__ */ React80.createElement(Container, { name: "profit-and-loss" }, children) : children);
6770
+ };
6771
+ ProfitAndLoss.Chart = ProfitAndLossChart;
6772
+ ProfitAndLoss.Context = PNLContext;
6773
+ ProfitAndLoss.DatePicker = ProfitAndLossDatePicker;
6774
+ ProfitAndLoss.Summaries = ProfitAndLossSummaries;
6775
+ ProfitAndLoss.Table = ProfitAndLossTable;
6776
+ ProfitAndLoss.DetailedCharts = ProfitAndLossDetailedCharts;
6777
+
6778
+ // src/components/ProfitAndLossView/ProfitAndLossView.tsx
6779
+ import React82, { useContext as useContext7, useRef as useRef14 } from "react";
6780
+
6781
+ // src/components/Panel/Panel.tsx
6782
+ import React81, { useEffect as useEffect12, useState as useState18 } from "react";
6783
+ import classNames29 from "classnames";
6784
+ var Panel = ({
6785
+ children,
6786
+ className,
6787
+ sidebar,
6788
+ header,
6789
+ sidebarIsOpen,
6790
+ parentRef
6791
+ }) => {
6792
+ const [sidebarHeight, setSidebarHeight] = useState18(0);
6793
+ useEffect12(() => {
6794
+ if (parentRef?.current?.offsetHeight) {
6795
+ setSidebarHeight(parentRef?.current?.offsetHeight - 1);
6796
+ }
6797
+ }, [parentRef?.current?.offsetHeight, sidebarIsOpen]);
6798
+ return /* @__PURE__ */ React81.createElement(
6799
+ "div",
6800
+ {
6801
+ className: classNames29(
6802
+ "Layer__panel",
6803
+ className,
6804
+ sidebarIsOpen && "Layer__panel--open"
6805
+ )
6806
+ },
6807
+ /* @__PURE__ */ React81.createElement("div", { className: "Layer__panel__content" }, header, children),
6808
+ sidebar && /* @__PURE__ */ React81.createElement(
6809
+ "div",
6810
+ {
6811
+ className: "Layer__panel__sidebar",
6812
+ style: {
6813
+ maxHeight: sidebarHeight > 0 && sidebarIsOpen ? sidebarHeight : 0
6814
+ }
6815
+ },
6816
+ /* @__PURE__ */ React81.createElement("div", { className: "Layer__panel__sidebar-content" }, sidebar)
6817
+ )
6818
+ );
6819
+ };
6820
+
6821
+ // src/components/ProfitAndLossView/ProfitAndLossView.tsx
6822
+ var COMPONENT_NAME3 = "profit-and-loss";
6823
+ var ProfitAndLossView = (props) => {
6824
+ const containerRef = useRef14(null);
6825
+ return /* @__PURE__ */ React82.createElement(Container, { name: COMPONENT_NAME3, ref: containerRef }, /* @__PURE__ */ React82.createElement(ProfitAndLoss, null, /* @__PURE__ */ React82.createElement(ProfitAndLossPanel, { containerRef, ...props })));
6826
+ };
6827
+ var ProfitAndLossPanel = ({
6828
+ containerRef,
6829
+ ...props
6830
+ }) => {
6831
+ const { sidebarScope } = useContext7(ProfitAndLoss.Context);
6832
+ return /* @__PURE__ */ React82.createElement(
6833
+ Panel,
6834
+ {
6835
+ sidebar: /* @__PURE__ */ React82.createElement(ProfitAndLossDetailedCharts, null),
6836
+ sidebarIsOpen: Boolean(sidebarScope),
6837
+ parentRef: containerRef
6838
+ },
6839
+ /* @__PURE__ */ React82.createElement(Header, { className: `Layer__${COMPONENT_NAME3}__header` }, /* @__PURE__ */ React82.createElement(Heading, { className: "Layer__profit-and-loss__title" }, "Profit & Loss")),
6840
+ /* @__PURE__ */ React82.createElement(Components, { ...props })
6841
+ );
6842
+ };
6843
+ var Components = ({
6844
+ hideChart = false,
6845
+ hideTable = false
6846
+ }) => {
6847
+ const { error, isLoading, isValidating, refetch } = useContext7(
6848
+ ProfitAndLoss.Context
6849
+ );
6850
+ if (!isLoading && error) {
6851
+ return /* @__PURE__ */ React82.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React82.createElement(
6852
+ DataState,
6853
+ {
6854
+ status: "failed" /* failed */,
6855
+ title: "Something went wrong",
6856
+ description: "We couldn\u2019t load your data.",
6857
+ onRefresh: () => refetch(),
6858
+ isLoading: isValidating
6859
+ }
6860
+ ));
6861
+ }
6862
+ return /* @__PURE__ */ React82.createElement(React82.Fragment, null, !hideChart && /* @__PURE__ */ React82.createElement("div", { className: `Layer__${COMPONENT_NAME3}__chart_with_summaries` }, /* @__PURE__ */ React82.createElement(
6863
+ "div",
6864
+ {
6865
+ className: `Layer__${COMPONENT_NAME3}__chart_with_summaries__summary-col`
6866
+ },
6867
+ /* @__PURE__ */ React82.createElement(ProfitAndLoss.DatePicker, null),
6868
+ /* @__PURE__ */ React82.createElement(ProfitAndLoss.Summaries, { vertical: true })
6869
+ ), /* @__PURE__ */ React82.createElement(
6870
+ "div",
6871
+ {
6872
+ className: `Layer__${COMPONENT_NAME3}__chart_with_summaries__chart-col`
6873
+ },
6874
+ /* @__PURE__ */ React82.createElement(ProfitAndLoss.Chart, null)
6875
+ )), !hideTable && /* @__PURE__ */ React82.createElement(ProfitAndLoss.Table, null));
6876
+ };
6877
+
6878
+ // src/components/ChartOfAccounts/ChartOfAccounts.tsx
6879
+ import React96, { createContext as createContext3, useContext as useContext14, useState as useState24 } from "react";
6880
+
6881
+ // src/hooks/useChartOfAccounts/useChartOfAccounts.tsx
6882
+ import { useState as useState19 } from "react";
6883
+ import useSWR6 from "swr";
6884
+ var validate = (formData) => {
6885
+ const errors = [];
6886
+ const nameError = validateName(formData);
6887
+ if (nameError) {
6888
+ errors.push(nameError);
6889
+ }
6890
+ return errors;
6891
+ };
6892
+ var revalidateField = (fieldName, formData) => {
6893
+ switch (fieldName) {
6894
+ case "name": {
6895
+ const nameError = validateName(formData);
6896
+ if (nameError) {
6897
+ return (formData?.errors || []).filter((x) => x.field !== fieldName).concat([nameError]);
6898
+ }
6899
+ return (formData?.errors || []).filter((x) => x.field !== fieldName);
6900
+ }
6901
+ default:
6902
+ return formData?.errors;
6903
+ }
6904
+ };
6905
+ var validateName = (formData) => {
6906
+ if (!formData?.data.name?.trim()) {
6907
+ return {
6908
+ field: "name",
6909
+ message: "Cannot be blank"
6910
+ };
6911
+ }
6912
+ return;
6913
+ };
6914
+ var flattenAccounts = (accounts) => accounts.flatMap((a) => [a, flattenAccounts(a.sub_accounts || [])]).flat().filter((id) => id);
6915
+ var useChartOfAccounts = () => {
6916
+ const { auth, businessId, apiUrl } = useLayerContext();
6917
+ const [form, setForm] = useState19();
6918
+ const [sendingForm, setSendingForm] = useState19(false);
6919
+ const [apiError, setApiError] = useState19(void 0);
6920
+ const { data, isLoading, isValidating, error, mutate } = useSWR6(
6921
+ businessId && auth?.access_token && `chart-of-accounts-${businessId}`,
6922
+ Layer.getLedgerAccountBalances(apiUrl, auth?.access_token, {
6923
+ params: { businessId }
6924
+ })
6925
+ );
6926
+ const create = async (newAccount) => {
6927
+ setSendingForm(true);
6928
+ setApiError(void 0);
6929
+ try {
6930
+ await Layer.createAccount(apiUrl, auth?.access_token, {
6931
+ params: { businessId },
6932
+ body: newAccount
6933
+ });
6934
+ await refetch();
6935
+ setForm(void 0);
6936
+ } catch (_err) {
6937
+ setApiError("Submit failed. Please, check your connection and try again.");
6938
+ } finally {
6939
+ setSendingForm(false);
6940
+ }
6941
+ };
6942
+ const update = async (accountData, accountId) => {
6943
+ setSendingForm(true);
6944
+ setApiError(void 0);
6945
+ const stable_name = convertToStableName(accountData.name);
6946
+ const newAccountData = {
6947
+ ...accountData,
6948
+ stable_name,
6949
+ pnl_category: "INCOME",
6950
+ //this field will be deprecated soon, but is still required
6951
+ always_show_in_pnl: false
6952
+ //this field will be deprecated soon, but is still required
6953
+ };
6954
+ try {
6955
+ await Layer.updateAccount(apiUrl, auth?.access_token, {
6956
+ params: { businessId, accountId },
6957
+ body: newAccountData
6958
+ });
6959
+ await refetch();
6960
+ setForm(void 0);
6961
+ } catch (_err) {
6962
+ setApiError("Submit failed. Please, check your connection and try again.");
6963
+ } finally {
6964
+ setSendingForm(false);
6965
+ }
6966
+ };
6967
+ const submitForm = () => {
6968
+ if (!form || !form.action) {
6969
+ return;
6970
+ }
6971
+ const errors = validate(form);
6972
+ if (errors.length > 0) {
6973
+ setForm({
6974
+ ...form,
6975
+ errors
6976
+ });
6977
+ return;
6978
+ }
6979
+ const data2 = {
6980
+ name: form.data.name ?? "",
6981
+ normality: form.data.subType?.value,
6982
+ parent_id: form.data.parent ? {
6983
+ type: "AccountId",
6984
+ id: form.data.parent.value
6985
+ } : void 0,
6986
+ account_type: form.data.type.value.toString(),
6987
+ account_subtype: form.data.subType?.value.toString()
6988
+ };
6989
+ if (form.action === "new") {
6990
+ create(data2);
6991
+ return;
6992
+ }
6993
+ if (form.action === "edit" && form.accountId) {
6994
+ update(data2, form.accountId);
6995
+ return;
6996
+ }
6997
+ };
6998
+ const addAccount = () => setForm({
6999
+ action: "new",
7000
+ accountId: void 0,
7001
+ data: {
7002
+ parent: void 0,
7003
+ name: void 0,
7004
+ type: {
7005
+ value: "ASSETS",
7006
+ label: "Assets"
7007
+ },
7008
+ subType: void 0
7009
+ }
7010
+ });
7011
+ const editAccount = (id) => {
7012
+ const allAccounts = flattenAccounts(data?.data?.accounts || []);
7013
+ const found = allAccounts?.find((x) => x.id === id);
7014
+ if (!found) {
7015
+ return;
7016
+ }
7017
+ const parent = allAccounts.find(
7018
+ (x) => x.sub_accounts?.find((el) => el.id === found.id)
7019
+ );
7020
+ setForm({
7021
+ action: "edit",
7022
+ accountId: id,
7023
+ data: {
7024
+ parent: parent ? {
7025
+ value: parent.id,
7026
+ label: parent.name
7027
+ } : void 0,
7028
+ name: found.name,
7029
+ type: {
7030
+ value: "ASSETS",
7031
+ label: "Assets"
7032
+ },
7033
+ subType: void 0
7034
+ }
7035
+ });
7036
+ };
7037
+ const cancelForm = () => setForm(void 0);
7038
+ const changeFormData = (fieldName, value) => {
7039
+ if (!form) {
7040
+ return;
7041
+ }
7042
+ const newFormData = {
7043
+ ...form,
7044
+ data: {
7045
+ ...form.data,
7046
+ [fieldName]: value
7047
+ }
7048
+ };
7049
+ const errors = revalidateField(fieldName, newFormData);
7050
+ setForm({
7051
+ ...newFormData,
7052
+ errors
7053
+ });
7054
+ };
7055
+ const refetch = () => mutate();
7056
+ return {
7057
+ data: data?.data,
7058
+ isLoading,
7059
+ isValidating,
7060
+ error,
7061
+ refetch,
7062
+ create,
7063
+ form,
7064
+ sendingForm,
7065
+ apiError,
7066
+ addAccount,
7067
+ editAccount,
7068
+ cancelForm,
7069
+ changeFormData,
7070
+ submitForm
7071
+ };
7072
+ };
7073
+
7074
+ // src/hooks/useLedgerAccounts/useLedgerAccounts.tsx
7075
+ import { useState as useState20 } from "react";
7076
+ import useSWR7 from "swr";
7077
+ var useLedgerAccounts = () => {
7078
+ const { auth, businessId, apiUrl } = useLayerContext();
7079
+ const [accountId, setAccountId] = useState20();
7080
+ const [selectedEntryId, setSelectedEntryId] = useState20();
7081
+ const { data, isLoading, isValidating, error, mutate } = useSWR7(
7082
+ businessId && accountId && auth?.access_token && `ledger-accounts-lines-${businessId}-${accountId}`,
7083
+ Layer.getLedgerAccountsLines(apiUrl, auth?.access_token, {
7084
+ params: { businessId, accountId }
7085
+ })
7086
+ );
7087
+ const {
7088
+ data: entryData,
7089
+ mutate: mutateEntryData,
7090
+ isLoading: isLoadingEntry,
7091
+ isValidating: isValdiatingEntry,
7092
+ error: errorEntry
7093
+ } = useSWR7(
7094
+ businessId && selectedEntryId && auth?.access_token && `ledger-accounts-entry-${businessId}-${selectedEntryId}}`,
7095
+ Layer.getLedgerAccountsEntry(apiUrl, auth?.access_token, {
7096
+ params: { businessId, entryId: selectedEntryId }
7097
+ })
7098
+ );
7099
+ const refetch = () => mutate();
7100
+ const closeSelectedEntry = () => {
7101
+ setSelectedEntryId(void 0);
7102
+ mutateEntryData();
7103
+ };
7104
+ return {
7105
+ data: data?.data,
7106
+ entryData: entryData?.data,
7107
+ isLoading,
7108
+ isLoadingEntry,
7109
+ isValidating,
7110
+ isValdiatingEntry,
7111
+ error,
7112
+ errorEntry,
7113
+ refetch,
7114
+ accountId,
7115
+ setAccountId,
7116
+ selectedEntryId,
7117
+ setSelectedEntryId,
7118
+ closeSelectedEntry
7119
+ };
6175
7120
  };
6176
7121
 
6177
- // src/components/ProfitAndLossDetailedCharts/DetailedTable.tsx
6178
- import React78 from "react";
7122
+ // src/components/ChartOfAccountsTable/ChartOfAccountsTable.tsx
7123
+ import React88, { useContext as useContext10 } from "react";
6179
7124
 
6180
- // src/icons/SortArrows.tsx
6181
- import * as React77 from "react";
6182
- var SortArrows = ({ size = 13, ...props }) => /* @__PURE__ */ React77.createElement(
7125
+ // src/components/ChartOfAccountsRow/ChartOfAccountsRow.tsx
7126
+ import React84, { useContext as useContext8, useEffect as useEffect13, useState as useState21 } from "react";
7127
+
7128
+ // src/icons/Edit2.tsx
7129
+ import * as React83 from "react";
7130
+ var Edit2 = ({ size = 18, ...props }) => /* @__PURE__ */ React83.createElement(
6183
7131
  "svg",
6184
7132
  {
6185
7133
  xmlns: "http://www.w3.org/2000/svg",
6186
- viewBox: "0 0 12 13",
7134
+ viewBox: "0 0 18 18",
6187
7135
  fill: "none",
6188
7136
  ...props,
6189
7137
  width: size,
6190
7138
  height: size
6191
7139
  },
6192
- /* @__PURE__ */ React77.createElement("g", { "clip-path": "url(#clip0_1758_75388)" }, /* @__PURE__ */ React77.createElement(
6193
- "path",
6194
- {
6195
- d: "M1.33325 8.5L3.99992 11.1667L6.66659 8.5",
6196
- stroke: "currentColor",
6197
- strokeLinecap: "round",
6198
- strokeLinejoin: "round",
6199
- className: "desc-arrow"
6200
- }
6201
- ), /* @__PURE__ */ React77.createElement(
6202
- "path",
6203
- {
6204
- d: "M4 2.5L4 11.1667",
6205
- stroke: "currentColor",
6206
- strokeLinecap: "round",
6207
- strokeLinejoin: "round",
6208
- className: "desc-arrow"
6209
- }
6210
- ), /* @__PURE__ */ React77.createElement(
6211
- "path",
6212
- {
6213
- d: "M5.99988 5.16602L8.66654 2.49935L11.3332 5.16602",
6214
- stroke: "currentColor",
6215
- strokeLinecap: "round",
6216
- strokeLinejoin: "round",
6217
- className: "asc-arrow"
6218
- }
6219
- ), /* @__PURE__ */ React77.createElement(
7140
+ /* @__PURE__ */ React83.createElement(
6220
7141
  "path",
6221
7142
  {
6222
- d: "M8.66663 11.166L8.66663 2.49935",
7143
+ d: "M12.75 2.25C12.947 2.05301 13.1808 1.89676 13.4382 1.79015C13.6956 1.68355 13.9714 1.62868 14.25 1.62868C14.5286 1.62868 14.8044 1.68355 15.0618 1.79015C15.3192 1.89676 15.553 2.05301 15.75 2.25C15.947 2.44698 16.1032 2.68083 16.2098 2.9382C16.3165 3.19557 16.3713 3.47142 16.3713 3.75C16.3713 4.02857 16.3165 4.30442 16.2098 4.56179C16.1032 4.81916 15.947 5.05302 15.75 5.25L5.625 15.375L1.5 16.5L2.625 12.375L12.75 2.25Z",
6223
7144
  stroke: "currentColor",
6224
7145
  strokeLinecap: "round",
6225
- strokeLinejoin: "round",
6226
- className: "asc-arrow"
6227
- }
6228
- )),
6229
- /* @__PURE__ */ React77.createElement("defs", null, /* @__PURE__ */ React77.createElement("clipPath", { id: "clip0_1758_75388" }, /* @__PURE__ */ React77.createElement(
6230
- "rect",
6231
- {
6232
- width: "12",
6233
- height: "12",
6234
- fill: "white",
6235
- transform: "translate(0 0.5)"
7146
+ strokeLinejoin: "round"
6236
7147
  }
6237
- )))
7148
+ )
6238
7149
  );
6239
- var SortArrows_default = SortArrows;
7150
+ var Edit2_default = Edit2;
6240
7151
 
6241
- // src/components/ProfitAndLossDetailedCharts/DetailedTable.tsx
6242
- import classNames27 from "classnames";
6243
- var DetailedTable = ({
6244
- filteredData,
6245
- sidebarScope,
6246
- filters,
6247
- sortBy,
6248
- hoveredItem,
6249
- setHoveredItem
7152
+ // src/components/ChartOfAccountsRow/ChartOfAccountsRow.tsx
7153
+ import classNames30 from "classnames";
7154
+ var INDENTATION = 24;
7155
+ var MOBILE_INDENTATION = 12;
7156
+ var EXPANDED_STYLE = {
7157
+ height: 52,
7158
+ paddingTop: 12,
7159
+ paddingBottom: 12,
7160
+ opacity: 1
7161
+ };
7162
+ var EXPANDED_MOBILE_STYLE = {
7163
+ height: 76,
7164
+ paddingTop: 12,
7165
+ paddingBottom: 12,
7166
+ opacity: 1
7167
+ };
7168
+ var COLLAPSED_STYLE = {
7169
+ height: 0,
7170
+ paddingTop: 0,
7171
+ paddingBottom: 0,
7172
+ opacity: 0.5
7173
+ };
7174
+ var ChartOfAccountsRow = ({
7175
+ account,
7176
+ depth = 0,
7177
+ index,
7178
+ cumulativeIndex = 0,
7179
+ expanded = false,
7180
+ defaultOpen = false,
7181
+ acountsLength,
7182
+ view
6250
7183
  }) => {
6251
- const buildColClass = (column) => {
6252
- return classNames27(
6253
- "Layer__sortable-col",
6254
- sidebarScope && filters[sidebarScope]?.sortBy === column ? `sort--${(sidebarScope && filters[sidebarScope]?.sortDirection) ?? "desc"}` : ""
6255
- );
7184
+ const { form, editAccount } = useContext8(ChartOfAccountsContext);
7185
+ const { setAccountId } = useContext8(LedgerAccountsContext);
7186
+ const baseStyle = view === "desktop" ? EXPANDED_STYLE : EXPANDED_MOBILE_STYLE;
7187
+ const [isOpen, setIsOpen] = useState21(defaultOpen);
7188
+ const style = expanded ? {
7189
+ ...baseStyle,
7190
+ transitionDelay: `${15 * index}ms`
7191
+ } : {
7192
+ ...COLLAPSED_STYLE,
7193
+ transitionDelay: `${acountsLength - 15 * index}ms`
6256
7194
  };
6257
- return /* @__PURE__ */ React78.createElement("div", { className: "details-container" }, /* @__PURE__ */ React78.createElement("div", { className: "table" }, /* @__PURE__ */ React78.createElement("table", null, /* @__PURE__ */ React78.createElement("thead", null, /* @__PURE__ */ React78.createElement("tr", null, /* @__PURE__ */ React78.createElement(
6258
- "th",
6259
- {
6260
- className: buildColClass("category"),
6261
- onClick: () => sortBy(sidebarScope ?? "expenses", "category")
6262
- },
6263
- "Expense/Sale ",
6264
- /* @__PURE__ */ React78.createElement(SortArrows_default, { className: "Layer__sort-arrows" })
6265
- ), /* @__PURE__ */ React78.createElement(
6266
- "th",
6267
- {
6268
- className: buildColClass("type"),
6269
- onClick: () => sortBy(sidebarScope ?? "expenses", "type")
6270
- },
6271
- "Type ",
6272
- /* @__PURE__ */ React78.createElement(SortArrows_default, { className: "Layer__sort-arrows" })
6273
- ), /* @__PURE__ */ React78.createElement("th", null), /* @__PURE__ */ React78.createElement(
6274
- "th",
7195
+ const [showComponent, setShowComponent] = useState21(false);
7196
+ useEffect13(() => {
7197
+ const timeoutId = setTimeout(() => {
7198
+ setShowComponent(true);
7199
+ }, cumulativeIndex * 50);
7200
+ return () => clearTimeout(timeoutId);
7201
+ }, []);
7202
+ const baseClass = classNames30(
7203
+ "Layer__table-row",
7204
+ isOpen ? "Layer__table-row--expanded" : "Layer__table-row--collapsed",
7205
+ !expanded && "Layer__table-row--hidden",
7206
+ `Layer__table-row--depth-${depth}`,
7207
+ form?.accountId === account.id && "Layer__table-row--active",
7208
+ !showComponent && "Layer__table-row--anim-starting-state"
7209
+ );
7210
+ const desktopRowClass = classNames30(
7211
+ baseClass,
7212
+ "Layer__chart-of-accounts__row---desktop"
7213
+ );
7214
+ const mobileRowClass = classNames30(
7215
+ baseClass,
7216
+ "Layer__chart-of-accounts__row---mobile"
7217
+ );
7218
+ return /* @__PURE__ */ React84.createElement(React84.Fragment, null, view === "desktop" && /* @__PURE__ */ React84.createElement(
7219
+ "tr",
6275
7220
  {
6276
- className: buildColClass("value"),
6277
- onClick: () => sortBy(sidebarScope ?? "expenses", "value")
7221
+ className: desktopRowClass,
7222
+ onClick: (e) => {
7223
+ e.preventDefault();
7224
+ e.stopPropagation();
7225
+ setAccountId(account.id);
7226
+ }
6278
7227
  },
6279
- "Value ",
6280
- /* @__PURE__ */ React78.createElement(SortArrows_default, { className: "Layer__sort-arrows" })
6281
- ))), /* @__PURE__ */ React78.createElement("tbody", null, filteredData.filter((x) => !x.hidden).map((item, idx) => {
6282
- const colorConfig = DEFAULT_CHART_COLORS[idx % DEFAULT_CHART_COLORS.length];
6283
- return /* @__PURE__ */ React78.createElement(
6284
- "tr",
7228
+ /* @__PURE__ */ React84.createElement("td", { className: "Layer__table-cell Layer__coa__name" }, /* @__PURE__ */ React84.createElement("span", { className: "Layer__table-cell-content", style }, /* @__PURE__ */ React84.createElement(
7229
+ "span",
6285
7230
  {
6286
- key: `pl-side-table-item-${idx}`,
6287
- className: classNames27(
6288
- "Layer__profit-and-loss-detailed-table__row",
6289
- hoveredItem && hoveredItem === item.display_name ? "active" : ""
6290
- ),
6291
- onMouseEnter: () => setHoveredItem(item.display_name),
6292
- onMouseLeave: () => setHoveredItem(void 0)
7231
+ className: "Layer__table-cell-content-indentation",
7232
+ style: {
7233
+ paddingLeft: INDENTATION * depth + 16
7234
+ }
6293
7235
  },
6294
- /* @__PURE__ */ React78.createElement("td", { className: "category-col" }, item.display_name),
6295
- /* @__PURE__ */ React78.createElement("td", { className: "type-col" }, item.type),
6296
- /* @__PURE__ */ React78.createElement("td", { className: "value-col" }, "$", centsToDollars(item.value)),
6297
- /* @__PURE__ */ React78.createElement("td", { className: "share-col" }, /* @__PURE__ */ React78.createElement("span", { className: "share-cell-content" }, formatPercent(item.share), "%", /* @__PURE__ */ React78.createElement(
6298
- "div",
7236
+ account.sub_accounts && account.sub_accounts.length > 0 && /* @__PURE__ */ React84.createElement(
7237
+ ChevronDownFill_default,
6299
7238
  {
6300
- className: "share-icon",
6301
- style: {
6302
- background: colorConfig.color,
6303
- opacity: colorConfig.opacity
7239
+ size: 16,
7240
+ className: "Layer__table__expand-icon",
7241
+ onClick: (e) => {
7242
+ e.stopPropagation();
7243
+ setIsOpen(!isOpen);
6304
7244
  }
6305
7245
  }
6306
- )))
6307
- );
6308
- })))));
6309
- };
6310
-
6311
- // src/components/ProfitAndLossDetailedCharts/Filters.tsx
6312
- import React79 from "react";
6313
- import Select3, { components as components3 } from "react-select";
6314
- var Filters = ({
6315
- filteredData,
6316
- sidebarScope,
6317
- filters,
6318
- setFilterTypes
6319
- }) => {
6320
- return /* @__PURE__ */ React79.createElement("div", { className: "filters" }, /* @__PURE__ */ React79.createElement(Text, { size: "sm" /* sm */, className: "Layer__label" }, "Filters"), /* @__PURE__ */ React79.createElement(
6321
- Select3,
6322
- {
6323
- className: "Layer__select type-select",
6324
- classNamePrefix: "Layer__select",
6325
- value: sidebarScope && filters[sidebarScope]?.types ? sidebarScope && filters[sidebarScope]?.types?.map((x) => ({
6326
- value: x,
6327
- label: x
6328
- })) : [],
6329
- isMulti: true,
6330
- isClearable: false,
6331
- options: [...new Set(filteredData?.map((x) => x.type))].map((x) => ({
6332
- label: x,
6333
- value: x
6334
- })),
6335
- onChange: (selected) => {
6336
- setFilterTypes(
6337
- sidebarScope ?? "expenses",
6338
- selected.map((x) => x.value)
6339
- );
6340
- },
6341
- components: {
6342
- DropdownIndicator: (props) => /* @__PURE__ */ React79.createElement(components3.DropdownIndicator, { ...props }, /* @__PURE__ */ React79.createElement(ChevronDown_default, null)),
6343
- Placeholder: (props) => /* @__PURE__ */ React79.createElement(components3.Placeholder, { ...props }, /* @__PURE__ */ React79.createElement("div", { className: "Layer__select__multi-all-placeholder-badge" }, "All"))
6344
- }
6345
- }
6346
- ));
6347
- };
6348
-
6349
- // src/components/ProfitAndLossDetailedCharts/ProfitAndLossDetailedCharts.tsx
6350
- import classNames28 from "classnames";
6351
- import { format as format6 } from "date-fns";
6352
- var ProfitAndLossDetailedCharts = () => {
6353
- const {
6354
- filteredData,
6355
- filteredTotal,
6356
- sortBy,
6357
- filters,
6358
- isLoading,
6359
- dateRange,
6360
- sidebarScope,
6361
- setSidebarScope,
6362
- setFilterTypes
6363
- } = useContext6(ProfitAndLoss.Context);
6364
- const [hoveredItem, setHoveredItem] = useState16();
6365
- return /* @__PURE__ */ React80.createElement(
6366
- "div",
6367
- {
6368
- className: classNames28(
6369
- "Layer__profit-and-loss__side-panel",
6370
- sidebarScope && "open"
6371
- )
6372
- },
6373
- /* @__PURE__ */ React80.createElement("div", { className: "Layer__profit-and-loss-detailed-charts" }, /* @__PURE__ */ React80.createElement("header", { className: "Layer__profit-and-loss-detailed-charts__header" }, /* @__PURE__ */ React80.createElement("div", { className: "Layer__profit-and-loss-detailed-charts__head" }, /* @__PURE__ */ React80.createElement(Text, { size: "lg" /* lg */, weight: "bold" /* bold */, className: "title" }, humanizeTitle(sidebarScope)), /* @__PURE__ */ React80.createElement(Text, { size: "sm" /* sm */, className: "date" }, format6(dateRange.startDate, "LLLL, y")), /* @__PURE__ */ React80.createElement(ProfitAndLossDatePicker, null)), /* @__PURE__ */ React80.createElement(
6374
- Button,
6375
- {
6376
- rightIcon: /* @__PURE__ */ React80.createElement(X_default, null),
6377
- iconOnly: true,
6378
- onClick: () => setSidebarScope(void 0),
6379
- variant: "secondary" /* secondary */
6380
- }
6381
- )), /* @__PURE__ */ React80.createElement("header", { className: "Layer__profit-and-loss-detailed-charts__header--tablet" }, /* @__PURE__ */ React80.createElement(BackButton, { onClick: () => setSidebarScope(void 0) })), /* @__PURE__ */ React80.createElement("div", { className: "Layer__profit-and-loss-detailed-charts__content" }, /* @__PURE__ */ React80.createElement(
6382
- DetailedChart,
7246
+ ),
7247
+ /* @__PURE__ */ React84.createElement("span", { className: "Layer__coa__name__text" }, account.name)
7248
+ ))),
7249
+ /* @__PURE__ */ React84.createElement("td", { className: "Layer__table-cell Layer__coa__type" }, /* @__PURE__ */ React84.createElement(
7250
+ "span",
6383
7251
  {
6384
- filteredData,
6385
- filteredTotal,
6386
- hoveredItem,
6387
- setHoveredItem,
6388
- sidebarScope,
6389
- date: dateRange.startDate
6390
- }
6391
- ), /* @__PURE__ */ React80.createElement("div", { className: "Layer__profit-and-loss-detailed-charts__table-wrapper" }, /* @__PURE__ */ React80.createElement(
6392
- Filters,
7252
+ className: "Layer__table-cell-content Layer__mobile--hidden",
7253
+ style
7254
+ },
7255
+ account.account_type?.display_name
7256
+ ), /* @__PURE__ */ React84.createElement(
7257
+ "span",
6393
7258
  {
6394
- filteredData,
6395
- sidebarScope,
6396
- filters,
6397
- setFilterTypes
6398
- }
6399
- ), /* @__PURE__ */ React80.createElement(
6400
- DetailedTable,
7259
+ className: "Layer__table-cell-content Layer__desktop--hidden",
7260
+ style
7261
+ },
7262
+ /* @__PURE__ */ React84.createElement(
7263
+ Text,
7264
+ {
7265
+ weight: "bold" /* bold */,
7266
+ className: "Layer__coa__type--mobile"
7267
+ },
7268
+ account.normality
7269
+ ),
7270
+ /* @__PURE__ */ React84.createElement(Text, { className: "Layer__coa__subtype--mobile" }, account.account_subtype?.display_name)
7271
+ )),
7272
+ /* @__PURE__ */ React84.createElement("td", { className: "Layer__table-cell Layer__coa__subtype Layer__mobile--hidden" }, /* @__PURE__ */ React84.createElement("span", { className: "Layer__table-cell-content", style }, account.account_subtype?.display_name)),
7273
+ /* @__PURE__ */ React84.createElement("td", { className: "Layer__table-cell Layer__coa__balance" }, /* @__PURE__ */ React84.createElement(
7274
+ "span",
6401
7275
  {
6402
- filteredData,
6403
- sidebarScope,
6404
- filters,
6405
- sortBy,
6406
- hoveredItem,
6407
- setHoveredItem
6408
- }
6409
- ))))
6410
- );
6411
- };
6412
-
6413
- // src/components/ProfitAndLossView/ProfitAndLossView.tsx
6414
- var COMPONENT_NAME3 = "profit-and-loss";
6415
- var ProfitAndLossView = (props) => {
6416
- return /* @__PURE__ */ React81.createElement(Container, { name: COMPONENT_NAME3 }, /* @__PURE__ */ React81.createElement(ProfitAndLoss, null, /* @__PURE__ */ React81.createElement("div", { className: `Layer__${COMPONENT_NAME3}__main-panel` }, /* @__PURE__ */ React81.createElement(Header, { className: `Layer__${COMPONENT_NAME3}__header` }, /* @__PURE__ */ React81.createElement(Heading, { className: "Layer__bank-transactions__title" }, "Profit & Loss")), /* @__PURE__ */ React81.createElement(Components, { ...props })), props.showDetailedCharts !== false && /* @__PURE__ */ React81.createElement(ProfitAndLossDetailedCharts, null)));
6417
- };
6418
- var Components = ({
6419
- hideChart = false,
6420
- hideTable = false
6421
- }) => {
6422
- const { error, isLoading, isValidating, refetch } = useContext7(
6423
- ProfitAndLoss.Context
6424
- );
6425
- if (!isLoading && error) {
6426
- return /* @__PURE__ */ React81.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React81.createElement(
6427
- DataState,
7276
+ className: "Layer__table-cell-content Layer__table-cell--amount",
7277
+ style
7278
+ },
7279
+ "$",
7280
+ centsToDollars(Math.abs(account.balance || 0))
7281
+ )),
7282
+ /* @__PURE__ */ React84.createElement("td", { className: "Layer__table-cell Layer__coa__actions" }, /* @__PURE__ */ React84.createElement("span", { className: "Layer__table-cell-content", style }, /* @__PURE__ */ React84.createElement(
7283
+ Button,
6428
7284
  {
6429
- status: "failed" /* failed */,
6430
- title: "Something went wrong",
6431
- description: "We couldn\u2019t load your data.",
6432
- onRefresh: () => refetch(),
6433
- isLoading: isValidating
6434
- }
6435
- ));
6436
- }
6437
- return /* @__PURE__ */ React81.createElement(React81.Fragment, null, !hideChart && /* @__PURE__ */ React81.createElement("div", { className: `Layer__${COMPONENT_NAME3}__chart_with_summaries` }, /* @__PURE__ */ React81.createElement(
6438
- "div",
7285
+ variant: "secondary" /* secondary */,
7286
+ rightIcon: /* @__PURE__ */ React84.createElement(Edit2_default, { size: 12 }),
7287
+ iconOnly: true,
7288
+ onClick: (e) => {
7289
+ e.preventDefault();
7290
+ e.stopPropagation();
7291
+ editAccount(account.id);
7292
+ }
7293
+ },
7294
+ "Edit"
7295
+ )))
7296
+ ), view === "mobile" || view === "tablet" ? /* @__PURE__ */ React84.createElement(
7297
+ "tr",
6439
7298
  {
6440
- className: `Layer__${COMPONENT_NAME3}__chart_with_summaries__summary-col`
7299
+ className: mobileRowClass,
7300
+ onClick: (e) => {
7301
+ e.preventDefault();
7302
+ e.stopPropagation();
7303
+ setAccountId(account.id);
7304
+ }
6441
7305
  },
6442
- /* @__PURE__ */ React81.createElement(ProfitAndLoss.DatePicker, null),
6443
- /* @__PURE__ */ React81.createElement(ProfitAndLoss.Summaries, { vertical: true })
6444
- ), /* @__PURE__ */ React81.createElement(
6445
- "div",
7306
+ /* @__PURE__ */ React84.createElement("td", { className: "Layer__table-cell", colSpan: 5 }, /* @__PURE__ */ React84.createElement(
7307
+ "span",
7308
+ {
7309
+ className: "Layer__table-cell-content Layer__table-cell-content-indentation",
7310
+ style: {
7311
+ paddingLeft: MOBILE_INDENTATION * depth + 16,
7312
+ ...style
7313
+ }
7314
+ },
7315
+ account.sub_accounts && account.sub_accounts.length > 0 && /* @__PURE__ */ React84.createElement(
7316
+ ChevronDownFill_default,
7317
+ {
7318
+ size: 16,
7319
+ className: "Layer__table__expand-icon",
7320
+ onClick: (e) => {
7321
+ e.stopPropagation();
7322
+ setIsOpen(!isOpen);
7323
+ }
7324
+ }
7325
+ ),
7326
+ /* @__PURE__ */ React84.createElement("div", { className: "Layer__chart-of-accounts__mobile-row-content" }, /* @__PURE__ */ React84.createElement("div", { className: "Layer__chart-of-accounts__mobile-row-content__top-row" }, /* @__PURE__ */ React84.createElement(
7327
+ Text,
7328
+ {
7329
+ as: "span",
7330
+ className: "Layer__chart-of-accounts__mobile-row-content__name"
7331
+ },
7332
+ account.name
7333
+ ), /* @__PURE__ */ React84.createElement(
7334
+ TextButton,
7335
+ {
7336
+ onClick: (e) => {
7337
+ e.preventDefault();
7338
+ e.stopPropagation();
7339
+ editAccount(account.id);
7340
+ }
7341
+ },
7342
+ "Edit"
7343
+ )), /* @__PURE__ */ React84.createElement("div", { className: "Layer__chart-of-accounts__mobile-row-content__bottom-row" }, /* @__PURE__ */ React84.createElement("div", { className: "Layer__chart-of-accounts__mobile-row-content__types" }, /* @__PURE__ */ React84.createElement(Text, { as: "span" }, account.normality), /* @__PURE__ */ React84.createElement("span", { className: "Layer__chart-of-accounts__mobile-row-content__separator" }), /* @__PURE__ */ React84.createElement(Text, { as: "span" }, "Sub-Type")), /* @__PURE__ */ React84.createElement(
7344
+ Text,
7345
+ {
7346
+ as: "span",
7347
+ className: "Layer__chart-of-accounts__mobile-row-content__balance"
7348
+ },
7349
+ "$",
7350
+ centsToDollars(Math.abs(account.balance || 0))
7351
+ )))
7352
+ ))
7353
+ ) : null, (account.sub_accounts || []).map((subAccount, idx) => /* @__PURE__ */ React84.createElement(
7354
+ ChartOfAccountsRow,
6446
7355
  {
6447
- className: `Layer__${COMPONENT_NAME3}__chart_with_summaries__chart-col`
6448
- },
6449
- /* @__PURE__ */ React81.createElement(ProfitAndLoss.Chart, null)
6450
- )), !hideTable && /* @__PURE__ */ React81.createElement(ProfitAndLoss.Table, null));
7356
+ key: subAccount.id,
7357
+ account: subAccount,
7358
+ depth: depth + 1,
7359
+ index: idx,
7360
+ expanded: isOpen && expanded,
7361
+ cumulativeIndex: cumulativeIndex + idx + 1,
7362
+ acountsLength: (account.sub_accounts ?? []).length,
7363
+ view
7364
+ }
7365
+ )));
6451
7366
  };
6452
7367
 
6453
- // src/components/LedgerAccounts/LedgerAccounts.tsx
6454
- import React88, { createContext as createContext3, useContext as useContext12 } from "react";
7368
+ // src/components/ChartOfAccountsSidebar/ChartOfAccountsSidebar.tsx
7369
+ import React87 from "react";
6455
7370
 
6456
- // src/hooks/useLedgerAccounts/useLedgerAccounts.tsx
6457
- import { useState as useState17 } from "react";
6458
- import useSWR6 from "swr";
6459
- var validate = (formData) => {
6460
- const errors = [];
6461
- const nameError = validateName(formData);
6462
- if (nameError) {
6463
- errors.push(nameError);
6464
- }
6465
- return errors;
6466
- };
6467
- var revalidateField = (fieldName, formData) => {
6468
- switch (fieldName) {
6469
- case "name":
6470
- const nameError = validateName(formData);
6471
- if (nameError) {
6472
- return (formData?.errors || []).filter((x) => x.field !== fieldName).concat([nameError]);
6473
- }
6474
- return (formData?.errors || []).filter((x) => x.field !== fieldName);
6475
- default:
6476
- return formData?.errors;
7371
+ // src/components/ChartOfAccountsForm/ChartOfAccountsForm.tsx
7372
+ import React86, { useContext as useContext9, useMemo as useMemo8 } from "react";
7373
+
7374
+ // src/components/ChartOfAccountsForm/constants.ts
7375
+ var SUB_TYPE_OPTIONS = [
7376
+ {
7377
+ value: "DEBIT" /* DEBIT */,
7378
+ label: "Debit"
7379
+ },
7380
+ {
7381
+ value: "CREDIT" /* CREDIT */,
7382
+ label: "Credit"
6477
7383
  }
6478
- };
6479
- var validateName = (formData) => {
6480
- if (!formData?.data.name?.trim()) {
7384
+ ];
7385
+
7386
+ // src/components/ChartOfAccountsForm/useParentOptions.ts
7387
+ import { useMemo as useMemo7 } from "react";
7388
+ var useParentOptions = (data) => useMemo7(
7389
+ () => flattenAccounts(data?.accounts || []).sort((a, b) => a?.name && b?.name ? a.name.localeCompare(b.name) : 0).map((x) => {
6481
7390
  return {
6482
- field: "name",
6483
- message: "Cannot be blank"
6484
- };
6485
- }
6486
- return;
6487
- };
6488
- var flattenAccounts = (accounts) => accounts.flatMap((a) => [a, flattenAccounts(a.sub_accounts || [])]).flat().filter((id) => id);
6489
- var useLedgerAccounts = () => {
6490
- const { auth, businessId, apiUrl } = useLayerContext();
6491
- const [form, setForm] = useState17();
6492
- const [sendingForm, setSendingForm] = useState17(false);
6493
- const [apiError, setApiError] = useState17(void 0);
6494
- const [showARForAccountId, setShowARForAccountId] = useState17();
6495
- const { data, isLoading, isValidating, error, mutate } = useSWR6(
6496
- businessId && auth?.access_token && `ledger-accounts-${businessId}`,
6497
- Layer.getLedgerAccounts(apiUrl, auth?.access_token, {
6498
- params: { businessId }
6499
- })
6500
- );
6501
- const create = async (newAccount) => {
6502
- setSendingForm(true);
6503
- setApiError(void 0);
6504
- try {
6505
- await Layer.createAccount(apiUrl, auth?.access_token, {
6506
- params: { businessId },
6507
- body: newAccount
6508
- });
6509
- await refetch();
6510
- setForm(void 0);
6511
- } catch (_err) {
6512
- setApiError("Submit failed. Please, check your connection and try again.");
6513
- } finally {
6514
- setSendingForm(false);
6515
- }
6516
- };
6517
- const update = async (accountData, accountId) => {
6518
- setSendingForm(true);
6519
- setApiError(void 0);
6520
- const stable_name = convertToStableName(accountData.name);
6521
- const newAccountData = {
6522
- ...accountData,
6523
- stable_name,
6524
- pnl_category: "INCOME",
6525
- //this field will be deprecated soon, but is still required
6526
- always_show_in_pnl: false
6527
- //this field will be deprecated soon, but is still required
6528
- };
6529
- try {
6530
- await Layer.updateAccount(apiUrl, auth?.access_token, {
6531
- params: { businessId, accountId },
6532
- body: newAccountData
6533
- });
6534
- await refetch();
6535
- setForm(void 0);
6536
- } catch (_err) {
6537
- setApiError("Submit failed. Please, check your connection and try again.");
6538
- } finally {
6539
- setSendingForm(false);
6540
- }
6541
- };
6542
- const submitForm = () => {
6543
- if (!form || !form.action) {
6544
- return;
6545
- }
6546
- const errors = validate(form);
6547
- if (errors.length > 0) {
6548
- setForm({
6549
- ...form,
6550
- errors
6551
- });
6552
- return;
6553
- }
6554
- const data2 = {
6555
- name: form.data.name || "Test name",
6556
- normality: form.data.subType?.value,
6557
- parent_id: form.data.parent ? {
6558
- type: "AccountId",
6559
- id: form.data.parent.value
6560
- } : void 0,
6561
- description: form.data.type?.value.toString() || "Test description"
7391
+ label: x.name,
7392
+ value: x.id
6562
7393
  };
6563
- if (form.action === "new") {
6564
- create(data2);
6565
- return;
6566
- }
6567
- if (form.action === "edit" && form.accountId) {
6568
- update(data2, form.accountId);
6569
- return;
7394
+ }),
7395
+ [data?.accounts?.length]
7396
+ );
7397
+
7398
+ // src/components/ChartOfAccountsForm/ChartOfAccountsForm.tsx
7399
+ var ChartOfAccountsForm = () => {
7400
+ const {
7401
+ form,
7402
+ data,
7403
+ changeFormData,
7404
+ cancelForm,
7405
+ submitForm,
7406
+ sendingForm,
7407
+ apiError
7408
+ } = useContext9(ChartOfAccountsContext);
7409
+ const parentOptions = useParentOptions(data);
7410
+ const entry = useMemo8(() => {
7411
+ if (form?.action === "edit" && form.accountId) {
7412
+ return flattenAccounts(data?.accounts || []).find(
7413
+ (x) => x.id === form.accountId
7414
+ );
6570
7415
  }
6571
- };
6572
- const addAccount = () => setForm({
6573
- action: "new",
6574
- accountId: void 0,
6575
- data: {
6576
- parent: void 0,
6577
- name: void 0,
6578
- type: {
6579
- value: "assets",
6580
- label: "Assets"
7416
+ return;
7417
+ }, [data, form?.accountId]);
7418
+ if (!form) {
7419
+ return;
7420
+ }
7421
+ return /* @__PURE__ */ React86.createElement(
7422
+ "form",
7423
+ {
7424
+ className: "Layer__form",
7425
+ onSubmit: (e) => {
7426
+ e.preventDefault();
7427
+ submitForm();
7428
+ }
7429
+ },
7430
+ /* @__PURE__ */ React86.createElement("div", { className: "Layer__chart-of-accounts__sidebar__header" }, /* @__PURE__ */ React86.createElement(Text, { size: "lg" /* lg */, weight: "bold" /* bold */, className: "title" }, form?.action === "edit" ? "Edit" : "Add New", " Account"), /* @__PURE__ */ React86.createElement("div", { className: "actions" }, /* @__PURE__ */ React86.createElement(
7431
+ Button,
7432
+ {
7433
+ type: "button",
7434
+ onClick: cancelForm,
7435
+ variant: "secondary" /* secondary */,
7436
+ disabled: sendingForm
6581
7437
  },
6582
- subType: void 0,
6583
- category: void 0
6584
- }
6585
- });
6586
- const editAccount = (id) => {
6587
- const allAccounts = flattenAccounts(data?.data?.accounts || []);
6588
- const found = allAccounts?.find((x) => x.id === id);
6589
- if (!found) {
6590
- return;
6591
- }
6592
- const parent = allAccounts.find(
6593
- (x) => x.sub_accounts?.find((el) => el.id === found.id)
6594
- );
6595
- setForm({
6596
- action: "edit",
6597
- accountId: id,
6598
- data: {
6599
- parent: parent ? {
6600
- value: parent.id,
6601
- label: parent.name
6602
- } : void 0,
6603
- name: found.name,
6604
- type: {
6605
- value: "assets",
6606
- label: "Assets"
6607
- },
6608
- subType: void 0,
6609
- category: void 0
7438
+ "Cancel"
7439
+ ), apiError && /* @__PURE__ */ React86.createElement(
7440
+ RetryButton,
7441
+ {
7442
+ type: "submit",
7443
+ processing: sendingForm,
7444
+ error: "Check connection and retry in few seconds.",
7445
+ disabled: sendingForm
7446
+ },
7447
+ "Retry"
7448
+ ), !apiError && /* @__PURE__ */ React86.createElement(
7449
+ SubmitButton,
7450
+ {
7451
+ type: "submit",
7452
+ noIcon: true,
7453
+ active: true,
7454
+ disabled: sendingForm
7455
+ },
7456
+ "Save"
7457
+ ))),
7458
+ apiError && /* @__PURE__ */ React86.createElement(
7459
+ Text,
7460
+ {
7461
+ size: "sm" /* sm */,
7462
+ className: "Layer__chart-of-accounts__form__error-message"
7463
+ },
7464
+ apiError
7465
+ ),
7466
+ entry && /* @__PURE__ */ React86.createElement("div", { className: "Layer__chart-of-accounts__form-edit-entry" }, /* @__PURE__ */ React86.createElement(Text, { weight: "bold" /* bold */ }, entry.name), /* @__PURE__ */ React86.createElement(Text, { weight: "bold" /* bold */ }, "$", centsToDollars(entry.balance || 0))),
7467
+ /* @__PURE__ */ React86.createElement("div", { className: "Layer__chart-of-accounts__form" }, /* @__PURE__ */ React86.createElement(InputGroup, { name: "parent", label: "Parent", inline: true }, /* @__PURE__ */ React86.createElement(
7468
+ Select2,
7469
+ {
7470
+ options: parentOptions,
7471
+ value: form?.data.parent,
7472
+ onChange: (sel) => changeFormData("parent", sel),
7473
+ disabled: sendingForm
7474
+ }
7475
+ )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "name", label: "Name", inline: true }, /* @__PURE__ */ React86.createElement(
7476
+ Input,
7477
+ {
7478
+ name: "name",
7479
+ placeholder: "Enter name...",
7480
+ value: form?.data.name,
7481
+ isInvalid: Boolean(form?.errors?.find((x) => x.field === "name")),
7482
+ errorMessage: form?.errors?.find((x) => x.field === "name")?.message,
7483
+ disabled: sendingForm,
7484
+ onChange: (e) => changeFormData("name", e.target.value)
6610
7485
  }
6611
- });
6612
- };
6613
- const cancelForm = () => setForm(void 0);
6614
- const changeFormData = (fieldName, value) => {
6615
- if (!form) {
6616
- return;
6617
- }
6618
- const newFormData = {
6619
- ...form,
6620
- data: {
6621
- ...form.data,
6622
- [fieldName]: value
7486
+ )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "type", label: "Type", inline: true }, /* @__PURE__ */ React86.createElement(
7487
+ Select2,
7488
+ {
7489
+ options: [],
7490
+ disabled: true,
7491
+ value: form?.data.type,
7492
+ onChange: (sel) => changeFormData("type", sel)
6623
7493
  }
6624
- };
6625
- const errors = revalidateField(fieldName, newFormData);
6626
- setForm({
6627
- ...newFormData,
6628
- errors
6629
- });
6630
- };
6631
- const refetch = () => mutate();
6632
- return {
6633
- data: data?.data,
6634
- isLoading,
6635
- isValidating,
6636
- error,
6637
- refetch,
6638
- create,
6639
- form,
6640
- sendingForm,
6641
- apiError,
6642
- addAccount,
6643
- editAccount,
6644
- cancelForm,
6645
- changeFormData,
6646
- submitForm,
6647
- showARForAccountId,
6648
- setShowARForAccountId
6649
- };
7494
+ )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "subType", label: "Sub-Type", inline: true }, /* @__PURE__ */ React86.createElement(
7495
+ Select2,
7496
+ {
7497
+ options: SUB_TYPE_OPTIONS,
7498
+ value: form?.data.subType,
7499
+ onChange: (sel) => changeFormData("subType", sel),
7500
+ disabled: sendingForm
7501
+ }
7502
+ )))
7503
+ );
6650
7504
  };
6651
7505
 
6652
- // src/components/AccountsReceivable/AccountsReceivableIndex.tsx
6653
- import React82, { useContext as useContext8, useMemo as useMemo7 } from "react";
6654
- import classNames29 from "classnames";
6655
- import { parseISO as parseISO9, format as formatTime7 } from "date-fns";
6656
- var AccountsReceivable = () => {
6657
- const { data, showARForAccountId, setShowARForAccountId } = useContext8(
6658
- LedgerAccountsContext
6659
- );
6660
- const entry = useMemo7(() => {
6661
- return flattenAccounts(data?.accounts || []).find(
6662
- (x) => x.id === showARForAccountId
6663
- );
6664
- }, [showARForAccountId]);
6665
- const baseClassName = classNames29(
6666
- "Layer__accounts-receivable__index",
6667
- showARForAccountId && "open"
6668
- );
6669
- const close = () => setShowARForAccountId(void 0);
6670
- return /* @__PURE__ */ React82.createElement("div", { className: baseClassName }, /* @__PURE__ */ React82.createElement("div", { className: "Layer__accounts-receivable__header" }, /* @__PURE__ */ React82.createElement(BackButton, { onClick: close }), /* @__PURE__ */ React82.createElement("div", { className: "Layer__accounts-receivable__title-container" }, /* @__PURE__ */ React82.createElement(
6671
- Text,
6672
- {
6673
- weight: "bold" /* bold */,
6674
- className: "Layer__accounts-receivable__title"
6675
- },
6676
- entry?.name || ""
6677
- ), /* @__PURE__ */ React82.createElement(
6678
- Button,
7506
+ // src/components/ChartOfAccountsSidebar/ChartOfAccountsSidebar.tsx
7507
+ var ChartOfAccountsSidebar = ({
7508
+ parentRef: _parentRef
7509
+ }) => {
7510
+ return /* @__PURE__ */ React87.createElement(ChartOfAccountsForm, null);
7511
+ };
7512
+
7513
+ // src/components/ChartOfAccountsTable/ChartOfAccountsTable.tsx
7514
+ var COMPONENT_NAME4 = "chart-of-accounts";
7515
+ var ChartOfAccountsTable = ({
7516
+ view,
7517
+ containerRef
7518
+ }) => {
7519
+ const { data, isLoading, addAccount, error, isValidating, refetch, form } = useContext10(ChartOfAccountsContext);
7520
+ let cumulativeIndex = 0;
7521
+ const accountsLength = data?.accounts.length ?? 0;
7522
+ return /* @__PURE__ */ React88.createElement(
7523
+ Panel,
6679
7524
  {
6680
- variant: "secondary" /* secondary */,
6681
- rightIcon: /* @__PURE__ */ React82.createElement(DownloadCloud_default, { size: 12 })
7525
+ sidebar: /* @__PURE__ */ React88.createElement(ChartOfAccountsSidebar, { parentRef: containerRef }),
7526
+ sidebarIsOpen: Boolean(form),
7527
+ parentRef: containerRef
6682
7528
  },
6683
- "Download"
6684
- )), /* @__PURE__ */ React82.createElement("div", { className: "Layer__accounts-receivable__balance-container" }, /* @__PURE__ */ React82.createElement(
7529
+ /* @__PURE__ */ React88.createElement(Header, { className: `Layer__${COMPONENT_NAME4}__header` }, /* @__PURE__ */ React88.createElement(Heading, { className: `Layer__${COMPONENT_NAME4}__title` }, "Chart of Accounts"), /* @__PURE__ */ React88.createElement("div", { className: `Layer__${COMPONENT_NAME4}__actions` }, /* @__PURE__ */ React88.createElement(
7530
+ Button,
7531
+ {
7532
+ variant: "secondary" /* secondary */,
7533
+ disabled: isLoading,
7534
+ rightIcon: /* @__PURE__ */ React88.createElement(DownloadCloud_default, { size: 12 })
7535
+ },
7536
+ "Download"
7537
+ ), /* @__PURE__ */ React88.createElement(Button, { onClick: () => addAccount(), disabled: isLoading }, "Add Account"))),
7538
+ /* @__PURE__ */ React88.createElement("table", { className: "Layer__chart-of-accounts__table" }, /* @__PURE__ */ React88.createElement("thead", null, /* @__PURE__ */ React88.createElement("tr", { className: "Layer__table-row--header" }, /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__name" }, "Name"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__type" }, "Type"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__subtype Layer__mobile--hidden" }, "Sub-Type"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__balance" }, "Balance"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__actions" }))), /* @__PURE__ */ React88.createElement("tbody", null, !error && data?.accounts.map((account, idx) => {
7539
+ const currentCumulativeIndex = cumulativeIndex;
7540
+ cumulativeIndex = (account.sub_accounts?.length || 0) + cumulativeIndex + 1;
7541
+ return /* @__PURE__ */ React88.createElement(
7542
+ ChartOfAccountsRow,
7543
+ {
7544
+ key: account.id,
7545
+ account,
7546
+ depth: 0,
7547
+ index: idx,
7548
+ cumulativeIndex: currentCumulativeIndex,
7549
+ expanded: true,
7550
+ defaultOpen: true,
7551
+ acountsLength: accountsLength,
7552
+ view
7553
+ }
7554
+ );
7555
+ }))),
7556
+ error ? /* @__PURE__ */ React88.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React88.createElement(
7557
+ DataState,
7558
+ {
7559
+ status: "failed" /* failed */,
7560
+ title: "Something went wrong",
7561
+ description: "We couldn\u2019t load your data.",
7562
+ onRefresh: () => refetch(),
7563
+ isLoading: isValidating || isLoading
7564
+ }
7565
+ )) : null,
7566
+ (!data || isLoading) && !error ? /* @__PURE__ */ React88.createElement("div", { className: `Layer__${COMPONENT_NAME4}__loader-container` }, /* @__PURE__ */ React88.createElement(Loader2, null)) : null,
7567
+ !isLoading && !error && data?.accounts.length === 0 ? /* @__PURE__ */ React88.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React88.createElement(
7568
+ DataState,
7569
+ {
7570
+ status: "info" /* info */,
7571
+ title: "Accounts were not found",
7572
+ description: 'New account can be created with "Add Account".',
7573
+ onRefresh: () => refetch(),
7574
+ isLoading: isValidating
7575
+ }
7576
+ )) : null
7577
+ );
7578
+ };
7579
+
7580
+ // src/components/LedgerAccount/LedgerAccountIndex.tsx
7581
+ import React95, {
7582
+ useContext as useContext13,
7583
+ useEffect as useEffect15,
7584
+ useMemo as useMemo10,
7585
+ useState as useState23
7586
+ } from "react";
7587
+
7588
+ // src/components/LedgerAccountEntryDetails/LedgerAccountEntryDetails.tsx
7589
+ import React93, { useContext as useContext11, useMemo as useMemo9 } from "react";
7590
+
7591
+ // src/components/Card/Card.tsx
7592
+ import React89 from "react";
7593
+ import classNames31 from "classnames";
7594
+ var Card = ({ children, className }) => {
7595
+ return /* @__PURE__ */ React89.createElement("div", { className: classNames31("Layer__card", className) }, children);
7596
+ };
7597
+
7598
+ // src/components/DateTime/DateTime.tsx
7599
+ import React90 from "react";
7600
+ import { parseISO as parseISO9, format as formatTime7 } from "date-fns";
7601
+ var DateTime = ({
7602
+ value,
7603
+ format: format7,
7604
+ dateFormat,
7605
+ timeFormat,
7606
+ onlyDate,
7607
+ onlyTime
7608
+ }) => {
7609
+ if (format7) {
7610
+ return /* @__PURE__ */ React90.createElement(Text, { className: "Layer__datetime" }, formatTime7(parseISO9(value), format7));
7611
+ }
7612
+ const date = formatTime7(parseISO9(value), dateFormat ?? DATE_FORMAT);
7613
+ const time = formatTime7(parseISO9(value), timeFormat ?? TIME_FORMAT);
7614
+ return /* @__PURE__ */ React90.createElement(Text, { className: "Layer__datetime" }, !onlyTime && /* @__PURE__ */ React90.createElement(
6685
7615
  Text,
6686
7616
  {
7617
+ as: "span",
6687
7618
  weight: "bold" /* bold */,
6688
- className: "Layer__accounts-receivable__balance-label"
7619
+ size: "sm" /* sm */,
7620
+ className: "Layer__datetime__date"
6689
7621
  },
6690
- "Current balance"
6691
- ), /* @__PURE__ */ React82.createElement(
7622
+ date
7623
+ ), !onlyDate && /* @__PURE__ */ React90.createElement(
6692
7624
  Text,
6693
7625
  {
7626
+ as: "span",
6694
7627
  weight: "bold" /* bold */,
6695
- className: "Layer__accounts-receivable__balance-value"
7628
+ size: "sm" /* sm */,
7629
+ className: "Layer__datetime__time"
6696
7630
  },
6697
- "$",
6698
- centsToDollars(entry?.balance || 0)
6699
- ))), /* @__PURE__ */ React82.createElement("table", { className: "Layer__table Layer__accounts-receivable-table" }, /* @__PURE__ */ React82.createElement("thead", null, /* @__PURE__ */ React82.createElement("tr", null, /* @__PURE__ */ React82.createElement("th", { className: "Layer__table-header" }, "Date"), /* @__PURE__ */ React82.createElement("th", { className: "Layer__table-header" }, "Journal id #"), /* @__PURE__ */ React82.createElement("th", { className: "Layer__table-header" }, "Source"), /* @__PURE__ */ React82.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Debit"), /* @__PURE__ */ React82.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Credit"), /* @__PURE__ */ React82.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Running balance"))), /* @__PURE__ */ React82.createElement("tbody", null, entry?.entries?.map((x) => {
6700
- return /* @__PURE__ */ React82.createElement("tr", { key: x.id }, /* @__PURE__ */ React82.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, x.createdAt && formatTime7(parseISO9(x.createdAt), DATE_FORMAT))), /* @__PURE__ */ React82.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, "#123")), /* @__PURE__ */ React82.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, "Invoice")), /* @__PURE__ */ React82.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, x.direction, " $X,XXX.XX")), /* @__PURE__ */ React82.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, "$X,XXX.XX")), /* @__PURE__ */ React82.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, /* @__PURE__ */ React82.createElement("span", { className: "Layer__table-cell-content" }, "$X,XXX.XX")));
6701
- }))));
7631
+ time
7632
+ ));
6702
7633
  };
6703
7634
 
6704
- // src/components/LedgerAccountsRow/LedgerAccountsRow.tsx
6705
- import React85, { useContext as useContext9, useEffect as useEffect11, useState as useState18 } from "react";
7635
+ // src/components/DetailsList/DetailsList.tsx
7636
+ import React91 from "react";
7637
+ import classNames32 from "classnames";
7638
+ var DetailsList = ({
7639
+ title,
7640
+ children,
7641
+ className,
7642
+ actions
7643
+ }) => {
7644
+ return /* @__PURE__ */ React91.createElement("div", { className: classNames32("Layer__details-list", className) }, title && /* @__PURE__ */ React91.createElement(Header, null, /* @__PURE__ */ React91.createElement(Heading, { size: "secondary" /* secondary */ }, title), actions && /* @__PURE__ */ React91.createElement("div", { className: "Layer__details-list__actions" }, actions)), /* @__PURE__ */ React91.createElement("ul", { className: "Layer__details-list__list" }, children));
7645
+ };
6706
7646
 
6707
- // src/icons/ArrowRightCircle.tsx
6708
- import * as React83 from "react";
6709
- var ArrowRightCircle = ({ size = 18, ...props }) => /* @__PURE__ */ React83.createElement(
6710
- "svg",
6711
- {
6712
- xmlns: "http://www.w3.org/2000/svg",
6713
- viewBox: "0 0 18 18",
6714
- fill: "none",
6715
- ...props,
6716
- width: size,
6717
- height: size
6718
- },
6719
- /* @__PURE__ */ React83.createElement(
6720
- "path",
6721
- {
6722
- d: "M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z",
6723
- stroke: "currentColor",
6724
- strokeLinecap: "round",
6725
- strokeLinejoin: "round"
7647
+ // src/components/DetailsList/DetailsListItem.tsx
7648
+ import React92 from "react";
7649
+ var renderValue = (value) => {
7650
+ if (typeof value === "string") {
7651
+ return /* @__PURE__ */ React92.createElement(Text, { weight: "bold" /* bold */, size: "sm" /* sm */ }, value);
7652
+ }
7653
+ return value;
7654
+ };
7655
+ var DetailsListItem = ({
7656
+ label,
7657
+ children,
7658
+ isLoading
7659
+ }) => {
7660
+ return /* @__PURE__ */ React92.createElement("li", { className: "Layer__details-list-item" }, /* @__PURE__ */ React92.createElement("label", { className: "Layer__details-list-item__label" }, label), /* @__PURE__ */ React92.createElement("span", { className: "Layer__details-list-item__value" }, isLoading ? /* @__PURE__ */ React92.createElement(SkeletonLoader, null) : renderValue(children)));
7661
+ };
7662
+
7663
+ // src/components/LedgerAccountEntryDetails/LedgerAccountEntryDetails.tsx
7664
+ var SourceDetailView = ({ source }) => {
7665
+ switch (source.type) {
7666
+ case "Transaction_Ledger_Entry_Source": {
7667
+ const transactionSource = source;
7668
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Account name" }, transactionSource.account_name), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Date" }, /* @__PURE__ */ React93.createElement(DateTime, { value: transactionSource.date })), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Amount" }, `$${centsToDollars(transactionSource.amount)}`), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Direction" }, transactionSource.direction), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Counterparty" }, transactionSource.counterparty));
6726
7669
  }
6727
- ),
6728
- /* @__PURE__ */ React83.createElement(
6729
- "path",
6730
- {
6731
- d: "M9 12L12 9L9 6",
6732
- stroke: "currentColor",
6733
- strokeLinecap: "round",
6734
- strokeLinejoin: "round"
7670
+ case "Invoice_Ledger_Entry_Source": {
7671
+ const invoiceSource = source;
7672
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Invoice number" }, invoiceSource.invoice_number), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Recipient name" }, invoiceSource.recipient_name), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Date" }, /* @__PURE__ */ React93.createElement(DateTime, { value: invoiceSource.date })), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Amount" }, `$${centsToDollars(invoiceSource.amount)}`));
6735
7673
  }
6736
- ),
6737
- /* @__PURE__ */ React83.createElement(
6738
- "path",
6739
- {
6740
- d: "M6 9H12",
6741
- stroke: "currentColor",
6742
- strokeLinecap: "round",
6743
- strokeLinejoin: "round"
7674
+ case "Manual_Ledger_Entry_Source": {
7675
+ const manualSource = source;
7676
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Memo" }, manualSource.memo), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Created by" }, manualSource.created_by));
6744
7677
  }
6745
- )
6746
- );
6747
- var ArrowRightCircle_default = ArrowRightCircle;
6748
-
6749
- // src/icons/Edit2.tsx
6750
- import * as React84 from "react";
6751
- var Edit2 = ({ size = 18, ...props }) => /* @__PURE__ */ React84.createElement(
6752
- "svg",
6753
- {
6754
- xmlns: "http://www.w3.org/2000/svg",
6755
- viewBox: "0 0 18 18",
6756
- fill: "none",
6757
- ...props,
6758
- width: size,
6759
- height: size
6760
- },
6761
- /* @__PURE__ */ React84.createElement(
6762
- "path",
6763
- {
6764
- d: "M12.75 2.25C12.947 2.05301 13.1808 1.89676 13.4382 1.79015C13.6956 1.68355 13.9714 1.62868 14.25 1.62868C14.5286 1.62868 14.8044 1.68355 15.0618 1.79015C15.3192 1.89676 15.553 2.05301 15.75 2.25C15.947 2.44698 16.1032 2.68083 16.2098 2.9382C16.3165 3.19557 16.3713 3.47142 16.3713 3.75C16.3713 4.02857 16.3165 4.30442 16.2098 4.56179C16.1032 4.81916 15.947 5.05302 15.75 5.25L5.625 15.375L1.5 16.5L2.625 12.375L12.75 2.25Z",
6765
- stroke: "currentColor",
6766
- strokeLinecap: "round",
6767
- strokeLinejoin: "round"
7678
+ case "Invoice_Payment_Ledger_Entry_Source": {
7679
+ const invoicePaymentSource = source;
7680
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Invoice number" }, invoicePaymentSource.invoice_number), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Amount" }, `$${centsToDollars(invoicePaymentSource.amount)}`));
6768
7681
  }
6769
- )
6770
- );
6771
- var Edit2_default = Edit2;
6772
-
6773
- // src/components/LedgerAccountsRow/LedgerAccountsRow.tsx
6774
- import classNames30 from "classnames";
6775
- var INDENTATION = 12;
6776
- var EXPANDED_STYLE = {
6777
- height: 52,
6778
- paddingTop: 12,
6779
- paddingBottom: 12,
6780
- opacity: 1
7682
+ case "Refund_Ledger_Entry_Source": {
7683
+ const refundSource = source;
7684
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Amount" }, `$${centsToDollars(refundSource.refunded_to_customer_amount)}`), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Recipient name" }, refundSource.recipient_name));
7685
+ }
7686
+ case "Opening_Balance_Ledger_Entry_Source": {
7687
+ const openingBalanceSource = source;
7688
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Account name" }, openingBalanceSource.account_name));
7689
+ }
7690
+ case "Payout_Ledger_Entry_Source": {
7691
+ const payoutSource = source;
7692
+ return /* @__PURE__ */ React93.createElement(React93.Fragment, null, /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Amount" }, `$${centsToDollars(payoutSource.paid_out_amount)}`), /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Processor" }, payoutSource.processor));
7693
+ }
7694
+ default:
7695
+ return null;
7696
+ }
6781
7697
  };
6782
- var COLLAPSED_STYLE = {
6783
- height: 0,
6784
- paddingTop: 0,
6785
- paddingBottom: 0,
6786
- opacity: 0.5
7698
+ var LedgerAccountEntryDetails = () => {
7699
+ const { entryData, isLoadingEntry, closeSelectedEntry, errorEntry } = useContext11(LedgerAccountsContext);
7700
+ const { totalDebit, totalCredit } = useMemo9(() => {
7701
+ let totalDebit2 = 0;
7702
+ let totalCredit2 = 0;
7703
+ entryData?.line_items?.forEach((item) => {
7704
+ if (item.direction === "CREDIT" /* CREDIT */) {
7705
+ totalCredit2 += item.amount || 0;
7706
+ } else if (item.direction === "DEBIT" /* DEBIT */) {
7707
+ totalDebit2 += item.amount || 0;
7708
+ }
7709
+ });
7710
+ return { totalDebit: totalDebit2, totalCredit: totalCredit2 };
7711
+ }, [entryData]);
7712
+ return /* @__PURE__ */ React93.createElement("div", { className: "Layer__ledger-account__entry-details" }, /* @__PURE__ */ React93.createElement("div", { className: "Layer__ledger-account__entry-details__back-btn" }, /* @__PURE__ */ React93.createElement(BackButton, { onClick: () => closeSelectedEntry() })), /* @__PURE__ */ React93.createElement(
7713
+ DetailsList,
7714
+ {
7715
+ title: "Transaction source",
7716
+ actions: /* @__PURE__ */ React93.createElement(
7717
+ IconButton,
7718
+ {
7719
+ icon: /* @__PURE__ */ React93.createElement(X_default, null),
7720
+ onClick: () => closeSelectedEntry(),
7721
+ className: "Layer__hidden-sm Layer__hidden-xs"
7722
+ }
7723
+ )
7724
+ },
7725
+ /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Source", isLoading: isLoadingEntry }, /* @__PURE__ */ React93.createElement(Badge, null, entryData?.source?.type)),
7726
+ entryData?.source?.display_description && /* @__PURE__ */ React93.createElement(SourceDetailView, { source: entryData?.source })
7727
+ ), /* @__PURE__ */ React93.createElement(
7728
+ DetailsList,
7729
+ {
7730
+ title: `Journal Entry ${entryData?.id.substring(0, 5)}`,
7731
+ className: "Layer__border-top"
7732
+ },
7733
+ /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Entry type", isLoading: isLoadingEntry }, humanizeEnum(entryData?.entry_type ?? "")),
7734
+ /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Date", isLoading: isLoadingEntry }, entryData?.entry_at && /* @__PURE__ */ React93.createElement(DateTime, { value: entryData?.entry_at })),
7735
+ /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Creation date", isLoading: isLoadingEntry }, entryData?.date && /* @__PURE__ */ React93.createElement(DateTime, { value: entryData?.date })),
7736
+ entryData?.reversal_id && /* @__PURE__ */ React93.createElement(DetailsListItem, { label: "Reversal", isLoading: isLoadingEntry }, entryData?.reversal_id.substring(0, 5))
7737
+ ), !isLoadingEntry && !errorEntry ? /* @__PURE__ */ React93.createElement("div", { className: "Layer__ledger-account__entry-details__line-items" }, /* @__PURE__ */ React93.createElement(Card, null, /* @__PURE__ */ React93.createElement("table", { className: "Layer__table Layer__ledger-account__entry-details__table" }, /* @__PURE__ */ React93.createElement("thead", null, /* @__PURE__ */ React93.createElement("tr", null, /* @__PURE__ */ React93.createElement("th", { className: "Layer__table-header" }, "Line items"), /* @__PURE__ */ React93.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Debit"), /* @__PURE__ */ React93.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Credit"))), /* @__PURE__ */ React93.createElement("tbody", null, entryData?.line_items?.map((item) => /* @__PURE__ */ React93.createElement("tr", { key: `ledger-line-item-${item.id}` }, /* @__PURE__ */ React93.createElement("td", { className: "Layer__table-cell" }, item.account?.name || ""), /* @__PURE__ */ React93.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, item.direction === "DEBIT" /* DEBIT */ && /* @__PURE__ */ React93.createElement(Badge, { variant: "warning" /* WARNING */ }, "$", centsToDollars(item.amount || 0))), /* @__PURE__ */ React93.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, item.direction === "CREDIT" /* CREDIT */ && /* @__PURE__ */ React93.createElement(Badge, { variant: "success" /* SUCCESS */ }, "$", centsToDollars(item.amount || 0))))), /* @__PURE__ */ React93.createElement("tr", { className: "Layer__table Layer__ledger-account__entry-details__table__total-row" }, /* @__PURE__ */ React93.createElement("td", { className: "Layer__table-cell" }, "Total"), /* @__PURE__ */ React93.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, "$", centsToDollars(totalDebit || 0)), /* @__PURE__ */ React93.createElement("td", { className: "Layer__table-cell Layer__table-cell--amount" }, "$", centsToDollars(totalCredit || 0))))))) : null);
6787
7738
  };
6788
- var LedgerAccountsRow = ({
6789
- account,
6790
- depth = 0,
7739
+
7740
+ // src/components/LedgerAccount/LedgerAccountRow.tsx
7741
+ import React94, { useContext as useContext12, useEffect as useEffect14, useState as useState22 } from "react";
7742
+ import classNames33 from "classnames";
7743
+ import { parseISO as parseISO10, format as formatTime8 } from "date-fns";
7744
+ var LedgerAccountRow = ({
7745
+ row,
6791
7746
  index,
6792
- cumulativeIndex = 0,
6793
- expanded = false,
6794
- defaultOpen = false,
6795
- acountsLength
7747
+ initialLoad,
7748
+ view
6796
7749
  }) => {
6797
- const { form, editAccount, setShowARForAccountId } = useContext9(
6798
- LedgerAccountsContext
6799
- );
6800
- const [isOpen, setIsOpen] = useState18(defaultOpen);
6801
- const style = expanded ? {
6802
- ...EXPANDED_STYLE,
6803
- transitionDelay: `${15 * index}ms`
6804
- } : {
6805
- ...COLLAPSED_STYLE,
6806
- transitionDelay: `${acountsLength - 15 * index}ms`
6807
- };
6808
- const [showComponent, setShowComponent] = useState18(false);
6809
- useEffect11(() => {
6810
- const timeoutId = setTimeout(() => {
7750
+ const { selectedEntryId, setSelectedEntryId, closeSelectedEntry } = useContext12(LedgerAccountsContext);
7751
+ const [showComponent, setShowComponent] = useState22(false);
7752
+ useEffect14(() => {
7753
+ if (initialLoad) {
7754
+ const timeoutId = setTimeout(() => {
7755
+ setShowComponent(true);
7756
+ }, index * 10);
7757
+ return () => clearTimeout(timeoutId);
7758
+ } else {
6811
7759
  setShowComponent(true);
6812
- }, cumulativeIndex * 50);
6813
- return () => clearTimeout(timeoutId);
7760
+ }
6814
7761
  }, []);
6815
- const baseClass = classNames30(
6816
- "Layer__table-row",
6817
- isOpen ? "Layer__table-row--expanded" : "Layer__table-row--collapsed",
6818
- !expanded && "Layer__table-row--hidden",
6819
- `Layer__table-row--depth-${depth}`,
6820
- form?.accountId === account.id && "Layer__table-row--active",
6821
- !showComponent && "Layer__table-row--anim-starting-state"
6822
- );
6823
- return /* @__PURE__ */ React85.createElement(React85.Fragment, null, /* @__PURE__ */ React85.createElement("tr", { className: baseClass, onClick: () => setIsOpen(!isOpen) }, /* @__PURE__ */ React85.createElement("td", { className: "Layer__table-cell Layer__coa__name" }, /* @__PURE__ */ React85.createElement("span", { className: "Layer__table-cell-content", style }, /* @__PURE__ */ React85.createElement(
6824
- "span",
6825
- {
6826
- className: "Layer__table-cell-content-indentation",
6827
- style: {
6828
- paddingLeft: INDENTATION * depth + 16
6829
- }
6830
- },
6831
- account.sub_accounts && account.sub_accounts.length > 0 && /* @__PURE__ */ React85.createElement(
6832
- ChevronDownFill_default,
7762
+ if (view === "tablet") {
7763
+ return /* @__PURE__ */ React94.createElement(
7764
+ "tr",
7765
+ {
7766
+ className: classNames33(
7767
+ "Layer__table-row",
7768
+ row.entry_id === selectedEntryId && "Layer__table-row--active",
7769
+ initialLoad && "initial-load",
7770
+ "Layer__table-row--with-show",
7771
+ showComponent ? "show" : "Layer__table-row--anim-starting-state"
7772
+ ),
7773
+ style: { transitionDelay: `${15 * index}ms` },
7774
+ onClick: () => {
7775
+ if (selectedEntryId === row.entry_id) {
7776
+ closeSelectedEntry();
7777
+ } else {
7778
+ setSelectedEntryId(row.entry_id);
7779
+ }
7780
+ }
7781
+ },
7782
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__ledger-account-table__tablet-main-col" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ React94.createElement("div", { className: "Layer__ledger-account-table__tablet-main-col__date" }, /* @__PURE__ */ React94.createElement(Text, null, row.date && formatTime8(parseISO10(row.date), DATE_FORMAT)), /* @__PURE__ */ React94.createElement(
7783
+ Text,
7784
+ {
7785
+ weight: "normal" /* normal */,
7786
+ className: "Layer__ledger_account-table__journal-id"
7787
+ },
7788
+ row.entry_id.substring(0, 5)
7789
+ )), /* @__PURE__ */ React94.createElement(Text, null, row.source?.display_description ?? ""))),
7790
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, row.direction === "DEBIT" /* DEBIT */ && `$${centsToDollars(row?.amount || 0)}`)),
7791
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, row.direction === "CREDIT" /* CREDIT */ && `$${centsToDollars(row?.amount || 0)}`)),
7792
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, `$${centsToDollars(row.running_balance)}`))
7793
+ );
7794
+ }
7795
+ if (view === "mobile") {
7796
+ return /* @__PURE__ */ React94.createElement(
7797
+ "tr",
6833
7798
  {
6834
- size: 16,
6835
- className: "Layer__table__expand-icon"
6836
- }
6837
- ),
6838
- /* @__PURE__ */ React85.createElement("span", { className: "Layer__coa__name__text" }, account.name)
6839
- ))), /* @__PURE__ */ React85.createElement("td", { className: "Layer__table-cell Layer__coa__type" }, /* @__PURE__ */ React85.createElement("span", { className: "Layer__table-cell-content", style }, account.normality)), /* @__PURE__ */ React85.createElement("td", { className: "Layer__table-cell Layer__coa__subtype" }, /* @__PURE__ */ React85.createElement("span", { className: "Layer__table-cell-content", style }, "Sub-Type")), /* @__PURE__ */ React85.createElement("td", { className: "Layer__table-cell Layer__coa__balance" }, /* @__PURE__ */ React85.createElement(
6840
- "span",
6841
- {
6842
- className: "Layer__table-cell-content Layer__table-cell--amount",
6843
- style
6844
- },
6845
- "$",
6846
- centsToDollars(Math.abs(account.balance || 0))
6847
- )), /* @__PURE__ */ React85.createElement("td", { className: "Layer__table-cell Layer__coa__actions" }, /* @__PURE__ */ React85.createElement("span", { className: "Layer__table-cell-content", style }, /* @__PURE__ */ React85.createElement(
6848
- Button,
6849
- {
6850
- variant: "secondary" /* secondary */,
6851
- rightIcon: /* @__PURE__ */ React85.createElement(Edit2_default, { size: 12 }),
6852
- onClick: (e) => {
6853
- e.preventDefault();
6854
- e.stopPropagation();
6855
- editAccount(account.id);
6856
- }
6857
- },
6858
- "Edit"
6859
- ), /* @__PURE__ */ React85.createElement(
6860
- Button,
7799
+ className: classNames33(
7800
+ "Layer__table-row",
7801
+ row.entry_id === selectedEntryId && "Layer__table-row--active",
7802
+ initialLoad && "initial-load",
7803
+ "Layer__table-row--with-show",
7804
+ showComponent ? "show" : "Layer__table-row--anim-starting-state"
7805
+ ),
7806
+ style: { transitionDelay: `${15 * index}ms` },
7807
+ onClick: () => {
7808
+ if (selectedEntryId === row.entry_id) {
7809
+ closeSelectedEntry();
7810
+ } else {
7811
+ setSelectedEntryId(row.entry_id);
7812
+ }
7813
+ }
7814
+ },
7815
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__ledger-account-table__tablet-main-col" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content" }, /* @__PURE__ */ React94.createElement("div", { className: "Layer__ledger-account-table__tablet-main-col__date" }, /* @__PURE__ */ React94.createElement(Text, null, row.date && formatTime8(parseISO10(row.date), DATE_FORMAT)), /* @__PURE__ */ React94.createElement(
7816
+ Text,
7817
+ {
7818
+ weight: "normal" /* normal */,
7819
+ className: "Layer__ledger_account-table__journal-id"
7820
+ },
7821
+ row.entry_id.substring(0, 5)
7822
+ )), /* @__PURE__ */ React94.createElement(Text, null, row.source?.display_description ?? ""), /* @__PURE__ */ React94.createElement("div", { className: "Layer__ledger_account-table__balances-mobile" }, /* @__PURE__ */ React94.createElement("div", { className: "Layer__ledger_account-table__balance-item" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__ledger_account-table__balances-mobile__label" }, "Debit"), /* @__PURE__ */ React94.createElement("span", { className: "Layer__ledger_account-table__balances-mobile__value" }, " ", row.direction === "DEBIT" /* DEBIT */ && `$${centsToDollars(row?.amount || 0)}`)), /* @__PURE__ */ React94.createElement("div", { className: "Layer__ledger_account-table__balance-item" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__ledger_account-table__balances-mobile__label" }, "Credit"), /* @__PURE__ */ React94.createElement("span", { className: "Layer__ledger_account-table__balances-mobile__value" }, row.direction === "CREDIT" /* CREDIT */ && `$${centsToDollars(row?.amount || 0)}`)), /* @__PURE__ */ React94.createElement("div", { className: "Layer__ledger_account-table__balance-item" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__ledger_account-table__balances-mobile__label" }, "Running balance"), /* @__PURE__ */ React94.createElement("span", { className: "Layer__ledger_account-table__balances-mobile__value" }, `$${centsToDollars(row.running_balance)}`)))))
7823
+ );
7824
+ }
7825
+ return /* @__PURE__ */ React94.createElement(
7826
+ "tr",
6861
7827
  {
6862
- variant: "secondary" /* secondary */,
6863
- rightIcon: /* @__PURE__ */ React85.createElement(ArrowRightCircle_default, { size: 12 }),
6864
- onClick: (e) => {
6865
- e.preventDefault();
6866
- e.stopPropagation();
6867
- setShowARForAccountId(account.id);
7828
+ className: classNames33(
7829
+ "Layer__table-row",
7830
+ row.entry_id === selectedEntryId && "Layer__table-row--active",
7831
+ initialLoad && "initial-load",
7832
+ "Layer__table-row--with-show",
7833
+ showComponent ? "show" : "Layer__table-row--anim-starting-state"
7834
+ ),
7835
+ style: { transitionDelay: `${15 * index}ms` },
7836
+ onClick: () => {
7837
+ if (selectedEntryId === row.entry_id) {
7838
+ closeSelectedEntry();
7839
+ } else {
7840
+ setSelectedEntryId(row.entry_id);
7841
+ }
6868
7842
  }
6869
7843
  },
6870
- "Open"
6871
- )))), (account.sub_accounts || []).map((subAccount, idx) => /* @__PURE__ */ React85.createElement(
6872
- LedgerAccountsRow,
6873
- {
6874
- key: subAccount.id,
6875
- account: subAccount,
6876
- depth: depth + 1,
6877
- index: idx,
6878
- expanded: isOpen && expanded,
6879
- cumulativeIndex: cumulativeIndex + idx + 1,
6880
- acountsLength: (account.sub_accounts ?? []).length
6881
- }
6882
- )));
7844
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content" }, row.date && formatTime8(parseISO10(row.date), DATE_FORMAT))),
7845
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content" }, row.entry_id.substring(0, 5))),
7846
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content" }, row.source?.display_description ?? "")),
7847
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, row.direction === "DEBIT" /* DEBIT */ && `$${centsToDollars(row?.amount || 0)}`)),
7848
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, row.direction === "CREDIT" /* CREDIT */ && `$${centsToDollars(row?.amount || 0)}`)),
7849
+ /* @__PURE__ */ React94.createElement("td", { className: "Layer__table-cell Layer__table-cell--primary" }, /* @__PURE__ */ React94.createElement("span", { className: "Layer__table-cell-content Layer__table-cell--amount" }, `$${centsToDollars(row.running_balance)}`))
7850
+ );
6883
7851
  };
6884
7852
 
6885
- // src/components/LedgerAccountsSidebar/LedgerAccountsSidebar.tsx
6886
- import React87, { useContext as useContext11 } from "react";
6887
-
6888
- // src/components/LedgerAccountsForm/LedgerAccountsForm.tsx
6889
- import React86, { useContext as useContext10, useMemo as useMemo8 } from "react";
6890
- var SUB_TYPE_OPTIONS = [
6891
- {
6892
- value: "DEBIT" /* DEBIT */,
6893
- label: "Debit"
6894
- },
6895
- {
6896
- value: "CREDIT" /* CREDIT */,
6897
- label: "Credit"
6898
- }
6899
- ];
6900
- var LedgerAccountsForm = () => {
7853
+ // src/components/LedgerAccount/LedgerAccountIndex.tsx
7854
+ import classNames34 from "classnames";
7855
+ var LedgerAccount = ({
7856
+ containerRef,
7857
+ pageSize = 15,
7858
+ view
7859
+ }) => {
7860
+ const [currentPage, setCurrentPage] = useState23(1);
7861
+ const [initialLoad, setInitialLoad] = useState23(true);
7862
+ const { data: accountData } = useContext13(ChartOfAccountsContext);
6901
7863
  const {
6902
- form,
6903
- data,
6904
- changeFormData,
6905
- cancelForm,
6906
- submitForm,
6907
- sendingForm,
6908
- apiError
6909
- } = useContext10(LedgerAccountsContext);
6910
- const parentOptions = useMemo8(
6911
- () => flattenAccounts(data?.accounts || []).sort((a, b) => a?.name && b?.name ? a.name.localeCompare(b.name) : 0).map((x) => {
6912
- return {
6913
- label: x.name,
6914
- value: x.id
6915
- };
6916
- }),
6917
- [data?.accounts?.length]
6918
- );
6919
- const entry = useMemo8(() => {
6920
- if (form?.action === "edit" && form.accountId) {
6921
- return flattenAccounts(data?.accounts || []).find(
6922
- (x) => x.id === form.accountId
6923
- );
7864
+ data: rawData,
7865
+ error,
7866
+ isLoading,
7867
+ isValidating,
7868
+ accountId,
7869
+ setAccountId,
7870
+ selectedEntryId,
7871
+ closeSelectedEntry,
7872
+ refetch
7873
+ } = useContext13(LedgerAccountsContext);
7874
+ useEffect15(() => {
7875
+ if (!isLoading) {
7876
+ const timeoutLoad = setTimeout(() => {
7877
+ setInitialLoad(false);
7878
+ }, 1e3);
7879
+ return () => clearTimeout(timeoutLoad);
6924
7880
  }
6925
- return;
6926
- }, [data, form?.accountId]);
6927
- if (!form) {
6928
- return;
6929
- }
6930
- return /* @__PURE__ */ React86.createElement(
6931
- "form",
7881
+ }, [isLoading]);
7882
+ const baseClassName = classNames34(
7883
+ "Layer__ledger-account__index",
7884
+ accountId && "open"
7885
+ );
7886
+ const entry = useMemo10(() => {
7887
+ return flattenAccounts(accountData?.accounts || []).find(
7888
+ (x) => x.id === accountId
7889
+ );
7890
+ }, [accountId]);
7891
+ const data = useMemo10(() => {
7892
+ const firstPageIndex = (currentPage - 1) * pageSize;
7893
+ const lastPageIndex = firstPageIndex + pageSize;
7894
+ return rawData?.sort((a, b) => Date.parse(b.date) - Date.parse(a.date))?.slice(firstPageIndex, lastPageIndex);
7895
+ }, [rawData, currentPage]);
7896
+ const close = () => {
7897
+ setAccountId(void 0);
7898
+ closeSelectedEntry();
7899
+ };
7900
+ return /* @__PURE__ */ React95.createElement(
7901
+ Panel,
6932
7902
  {
6933
- className: "Layer__form",
6934
- onSubmit: (e) => {
6935
- e.preventDefault();
6936
- submitForm();
6937
- }
7903
+ sidebar: /* @__PURE__ */ React95.createElement(LedgerAccountEntryDetails, null),
7904
+ sidebarIsOpen: Boolean(selectedEntryId),
7905
+ parentRef: containerRef,
7906
+ className: "Layer__ledger-account__panel"
6938
7907
  },
6939
- /* @__PURE__ */ React86.createElement("div", { className: "Layer__ledger-accounts__sidebar__header" }, /* @__PURE__ */ React86.createElement(Text, { size: "lg" /* lg */, weight: "bold" /* bold */, className: "title" }, form?.action === "edit" ? "Edit" : "Add New", " Account"), /* @__PURE__ */ React86.createElement("div", { className: "actions" }, /* @__PURE__ */ React86.createElement(
6940
- Button,
7908
+ /* @__PURE__ */ React95.createElement("div", { className: baseClassName }, /* @__PURE__ */ React95.createElement("div", { className: "Layer__ledger-account__header" }, /* @__PURE__ */ React95.createElement(BackButton, { onClick: close }), /* @__PURE__ */ React95.createElement("div", { className: "Layer__ledger-account__title-container" }, /* @__PURE__ */ React95.createElement(
7909
+ Text,
6941
7910
  {
6942
- type: "button",
6943
- onClick: cancelForm,
6944
- variant: "secondary" /* secondary */,
6945
- disabled: sendingForm
7911
+ weight: "bold" /* bold */,
7912
+ className: "Layer__ledger-account__title"
6946
7913
  },
6947
- "Cancel"
6948
- ), apiError && /* @__PURE__ */ React86.createElement(
6949
- RetryButton,
7914
+ entry?.name ?? ""
7915
+ ), /* @__PURE__ */ React95.createElement(
7916
+ Button,
6950
7917
  {
6951
- type: "submit",
6952
- processing: sendingForm,
6953
- error: "Check connection and retry in few seconds.",
6954
- disabled: sendingForm
7918
+ variant: "secondary" /* secondary */,
7919
+ rightIcon: /* @__PURE__ */ React95.createElement(DownloadCloud_default, { size: 12 })
6955
7920
  },
6956
- "Retry"
6957
- ), !apiError && /* @__PURE__ */ React86.createElement(
6958
- SubmitButton,
7921
+ "Download"
7922
+ )), /* @__PURE__ */ React95.createElement("div", { className: "Layer__ledger-account__balance-container" }, /* @__PURE__ */ React95.createElement(
7923
+ Text,
6959
7924
  {
6960
- type: "submit",
6961
- noIcon: true,
6962
- active: true,
6963
- disabled: sendingForm
7925
+ weight: "bold" /* bold */,
7926
+ className: "Layer__ledger-account__balance-label"
6964
7927
  },
6965
- "Save"
6966
- ))),
6967
- apiError && /* @__PURE__ */ React86.createElement(
7928
+ "Current balance"
7929
+ ), /* @__PURE__ */ React95.createElement(
6968
7930
  Text,
6969
7931
  {
6970
- size: "sm" /* sm */,
6971
- className: "Layer__ledger-accounts__form__error-message"
7932
+ weight: "bold" /* bold */,
7933
+ className: "Layer__ledger-account__balance-value"
6972
7934
  },
6973
- apiError
6974
- ),
6975
- entry && /* @__PURE__ */ React86.createElement("div", { className: "Layer__ledger-accounts__form-edit-entry" }, /* @__PURE__ */ React86.createElement(Text, { weight: "bold" /* bold */ }, entry.name), /* @__PURE__ */ React86.createElement(Text, { weight: "bold" /* bold */ }, "$", centsToDollars(entry.balance || 0))),
6976
- /* @__PURE__ */ React86.createElement("div", { className: "Layer__ledger-accounts__form" }, /* @__PURE__ */ React86.createElement(InputGroup, { name: "parent", label: "Parent", inline: true }, /* @__PURE__ */ React86.createElement(
6977
- Select2,
6978
- {
6979
- options: parentOptions,
6980
- value: form?.data.parent,
6981
- onChange: (sel) => changeFormData("parent", sel),
6982
- disabled: sendingForm
6983
- }
6984
- )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "name", label: "Name", inline: true }, /* @__PURE__ */ React86.createElement(
6985
- Input,
7935
+ "$",
7936
+ centsToDollars(entry?.balance || 0)
7937
+ ))), /* @__PURE__ */ React95.createElement("table", { className: "Layer__table Layer__table--hover-effect Layer__ledger-account-table" }, /* @__PURE__ */ React95.createElement("thead", null, /* @__PURE__ */ React95.createElement("tr", null, view !== "desktop" && /* @__PURE__ */ React95.createElement("th", null), view === "desktop" && /* @__PURE__ */ React95.createElement(React95.Fragment, null, /* @__PURE__ */ React95.createElement("th", { className: "Layer__table-header" }, "Date"), /* @__PURE__ */ React95.createElement("th", { className: "Layer__table-header" }, "Journal id #"), /* @__PURE__ */ React95.createElement("th", { className: "Layer__table-header" }, "Source")), view !== "mobile" && /* @__PURE__ */ React95.createElement(React95.Fragment, null, /* @__PURE__ */ React95.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Debit"), /* @__PURE__ */ React95.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Credit"), /* @__PURE__ */ React95.createElement("th", { className: "Layer__table-header Layer__table-cell--amount" }, "Running balance")))), /* @__PURE__ */ React95.createElement("tbody", null, data?.map((x, index) => /* @__PURE__ */ React95.createElement(
7938
+ LedgerAccountRow,
6986
7939
  {
6987
- name: "name",
6988
- placeholder: "Enter name...",
6989
- value: form?.data.name,
6990
- isInvalid: Boolean(form?.errors?.find((x) => x.field === "name")),
6991
- errorMessage: form?.errors?.find((x) => x.field === "name")?.message,
6992
- disabled: sendingForm,
6993
- onChange: (e) => changeFormData("name", e.target.value)
7940
+ key: x.id,
7941
+ row: x,
7942
+ index,
7943
+ initialLoad,
7944
+ view
6994
7945
  }
6995
- )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "type", label: "Type", inline: true }, /* @__PURE__ */ React86.createElement(
6996
- Select2,
7946
+ )))), data && /* @__PURE__ */ React95.createElement("div", { className: "Layer__ledger-account__pagination" }, /* @__PURE__ */ React95.createElement(
7947
+ Pagination,
6997
7948
  {
6998
- options: [],
6999
- disabled: true,
7000
- value: form?.data.type,
7001
- onChange: (sel) => changeFormData("type", sel)
7949
+ currentPage,
7950
+ totalCount: rawData?.length || 0,
7951
+ pageSize,
7952
+ onPageChange: (page) => setCurrentPage(page)
7002
7953
  }
7003
- )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "subType", label: "Sub-Type", inline: true }, /* @__PURE__ */ React86.createElement(
7004
- Select2,
7954
+ )), error ? /* @__PURE__ */ React95.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React95.createElement(
7955
+ DataState,
7005
7956
  {
7006
- options: SUB_TYPE_OPTIONS,
7007
- value: form?.data.subType,
7008
- onChange: (sel) => changeFormData("subType", sel),
7009
- disabled: sendingForm
7957
+ status: "failed" /* failed */,
7958
+ title: "Something went wrong",
7959
+ description: "We couldn\u2019t load your data.",
7960
+ onRefresh: () => refetch(),
7961
+ isLoading: isValidating || isLoading
7010
7962
  }
7011
- )), /* @__PURE__ */ React86.createElement(InputGroup, { name: "category", label: "Category", inline: true }, /* @__PURE__ */ React86.createElement(
7012
- Select2,
7963
+ )) : null, (!data || isLoading) && !error ? /* @__PURE__ */ React95.createElement("div", { className: `Layer__ledger-account__loader-container` }, /* @__PURE__ */ React95.createElement(Loader2, null)) : null, !isLoading && !error && data?.length === 0 ? /* @__PURE__ */ React95.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React95.createElement(
7964
+ DataState,
7013
7965
  {
7014
- options: [],
7015
- value: form?.data.category,
7016
- onChange: (sel) => changeFormData("category", sel),
7017
- disabled: sendingForm
7966
+ status: "info" /* info */,
7967
+ title: "No records found",
7968
+ onRefresh: () => refetch(),
7969
+ isLoading: isValidating
7018
7970
  }
7019
- )))
7971
+ )) : null)
7020
7972
  );
7021
7973
  };
7022
7974
 
7023
- // src/components/LedgerAccountsSidebar/LedgerAccountsSidebar.tsx
7024
- import classNames31 from "classnames";
7025
- var LedgerAccountsSidebar = () => {
7026
- const { form } = useContext11(LedgerAccountsContext);
7027
- return /* @__PURE__ */ React87.createElement(
7028
- "div",
7029
- {
7030
- className: classNames31(
7031
- "Layer__ledger-accounts__sidebar",
7032
- form ? "open" : ""
7033
- )
7975
+ // src/components/ChartOfAccounts/ChartOfAccounts.tsx
7976
+ var ChartOfAccountsContext = createContext3(
7977
+ {
7978
+ data: void 0,
7979
+ isLoading: false,
7980
+ isValidating: false,
7981
+ error: void 0,
7982
+ refetch: () => {
7034
7983
  },
7035
- /* @__PURE__ */ React87.createElement("div", { className: "Layer__ledger-accounts__sidebar-content" }, /* @__PURE__ */ React87.createElement(LedgerAccountsForm, null))
7036
- );
7037
- };
7038
-
7039
- // src/components/LedgerAccounts/LedgerAccounts.tsx
7040
- var COMPONENT_NAME4 = "ledger-accounts";
7984
+ create: () => {
7985
+ },
7986
+ form: void 0,
7987
+ sendingForm: false,
7988
+ apiError: void 0,
7989
+ addAccount: () => {
7990
+ },
7991
+ editAccount: () => {
7992
+ },
7993
+ cancelForm: () => {
7994
+ },
7995
+ changeFormData: () => {
7996
+ },
7997
+ submitForm: () => {
7998
+ }
7999
+ }
8000
+ );
7041
8001
  var LedgerAccountsContext = createContext3({
7042
8002
  data: void 0,
8003
+ entryData: void 0,
7043
8004
  isLoading: false,
8005
+ isLoadingEntry: false,
7044
8006
  isValidating: false,
8007
+ isValidatingEntry: false,
7045
8008
  error: void 0,
8009
+ errorEntry: void 0,
7046
8010
  refetch: () => {
7047
8011
  },
7048
- create: () => {
7049
- },
7050
- form: void 0,
7051
- sendingForm: false,
7052
- apiError: void 0,
7053
- addAccount: () => {
7054
- },
7055
- editAccount: () => {
8012
+ accountId: void 0,
8013
+ setAccountId: () => {
7056
8014
  },
7057
- cancelForm: () => {
8015
+ selectedEntryId: void 0,
8016
+ setSelectedEntryId: () => {
7058
8017
  },
7059
- changeFormData: () => {
7060
- },
7061
- submitForm: () => {
7062
- },
7063
- showARForAccountId: void 0,
7064
- setShowARForAccountId: () => {
8018
+ closeSelectedEntry: () => {
7065
8019
  }
7066
8020
  });
7067
- var LedgerAccounts = () => {
7068
- const contextData = useLedgerAccounts();
7069
- return /* @__PURE__ */ React88.createElement(LedgerAccountsContext.Provider, { value: contextData }, /* @__PURE__ */ React88.createElement(LedgerAccountsContent, null));
8021
+ var ChartOfAccounts = (props) => {
8022
+ const chartOfAccountsContextData = useChartOfAccounts();
8023
+ const ledgerAccountsContextData = useLedgerAccounts();
8024
+ return /* @__PURE__ */ React96.createElement(ChartOfAccountsContext.Provider, { value: chartOfAccountsContextData }, /* @__PURE__ */ React96.createElement(LedgerAccountsContext.Provider, { value: ledgerAccountsContextData }, /* @__PURE__ */ React96.createElement(ChartOfAccountsContent, null)));
7070
8025
  };
7071
- var LedgerAccountsContent = () => {
7072
- const { data, isLoading, addAccount, error, isValidating, refetch } = useContext12(LedgerAccountsContext);
7073
- let cumulativeIndex = 0;
7074
- const accountsLength = data?.accounts.length ?? 0;
7075
- return /* @__PURE__ */ React88.createElement(Container, { name: COMPONENT_NAME4 }, /* @__PURE__ */ React88.createElement("div", { className: `Layer__${COMPONENT_NAME4}__main-panel` }, /* @__PURE__ */ React88.createElement(Header, { className: `Layer__${COMPONENT_NAME4}__header` }, /* @__PURE__ */ React88.createElement(Heading, { className: `Layer__${COMPONENT_NAME4}__title` }, "Chart of Accounts"), /* @__PURE__ */ React88.createElement("div", { className: `Layer__${COMPONENT_NAME4}__actions` }, /* @__PURE__ */ React88.createElement(
7076
- Button,
7077
- {
7078
- variant: "secondary" /* secondary */,
7079
- disabled: isLoading,
7080
- rightIcon: /* @__PURE__ */ React88.createElement(DownloadCloud_default, { size: 12 })
7081
- },
7082
- "Download"
7083
- ), /* @__PURE__ */ React88.createElement(Button, { onClick: () => addAccount(), disabled: isLoading }, "Add Account"))), /* @__PURE__ */ React88.createElement("table", { className: `Layer__${COMPONENT_NAME4}__table` }, /* @__PURE__ */ React88.createElement("thead", null, /* @__PURE__ */ React88.createElement("tr", { className: "Layer__table-row--header" }, /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__name" }, "Name"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__type" }, "Type"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__subtype" }, "Sub-Type"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__balance" }, "Balance"), /* @__PURE__ */ React88.createElement("th", { className: "Layer__table-header Layer__coa__actions" }))), /* @__PURE__ */ React88.createElement("tbody", null, !error && data?.accounts.map((account, idx) => {
7084
- const currentCumulativeIndex = cumulativeIndex;
7085
- cumulativeIndex = (account.sub_accounts?.length || 0) + cumulativeIndex + 1;
7086
- return /* @__PURE__ */ React88.createElement(
7087
- LedgerAccountsRow,
7088
- {
7089
- key: account.id,
7090
- account,
7091
- depth: 0,
7092
- index: idx,
7093
- cumulativeIndex: currentCumulativeIndex,
7094
- expanded: true,
7095
- defaultOpen: true,
7096
- acountsLength: accountsLength
8026
+ var ChartOfAccountsContent = ({ asWidget }) => {
8027
+ const { accountId } = useContext14(LedgerAccountsContext);
8028
+ const [view, setView] = useState24("desktop");
8029
+ const containerRef = useElementSize((_a, _b, { width }) => {
8030
+ if (width) {
8031
+ if (width >= BREAKPOINTS.TABLET && view !== "desktop") {
8032
+ setView("desktop");
8033
+ } else if (width <= BREAKPOINTS.TABLET && width > BREAKPOINTS.MOBILE && view !== "tablet") {
8034
+ setView("tablet");
8035
+ } else if (width < BREAKPOINTS.MOBILE && view !== "mobile") {
8036
+ setView("mobile");
7097
8037
  }
7098
- );
7099
- }))), error ? /* @__PURE__ */ React88.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React88.createElement(
7100
- DataState,
7101
- {
7102
- status: "failed" /* failed */,
7103
- title: "Something went wrong",
7104
- description: "We couldn\u2019t load your data.",
7105
- onRefresh: () => refetch(),
7106
- isLoading: isValidating || isLoading
7107
- }
7108
- )) : null, (!data || isLoading) && !error ? /* @__PURE__ */ React88.createElement("div", { className: `Layer__${COMPONENT_NAME4}__loader-container` }, /* @__PURE__ */ React88.createElement(Loader2, null)) : null, !isLoading && !error && data?.accounts.length === 0 ? /* @__PURE__ */ React88.createElement("div", { className: "Layer__table-state-container" }, /* @__PURE__ */ React88.createElement(
7109
- DataState,
7110
- {
7111
- status: "info" /* info */,
7112
- title: "Accounts were not found",
7113
- description: 'New account can be created with "Add Account".',
7114
- onRefresh: () => refetch(),
7115
- isLoading: isValidating
7116
8038
  }
7117
- )) : null), /* @__PURE__ */ React88.createElement(LedgerAccountsSidebar, null), /* @__PURE__ */ React88.createElement(AccountsReceivable, null));
8039
+ });
8040
+ return /* @__PURE__ */ React96.createElement(Container, { name: "chart-of-accounts", ref: containerRef, asWidget }, accountId ? /* @__PURE__ */ React96.createElement(LedgerAccount, { view, containerRef }) : /* @__PURE__ */ React96.createElement(ChartOfAccountsTable, { view, containerRef }));
7118
8041
  };
7119
8042
 
7120
8043
  // src/providers/LayerProvider/LayerProvider.tsx
7121
- import React89, { useReducer, useEffect as useEffect12 } from "react";
8044
+ import React97, { useReducer, useEffect as useEffect16 } from "react";
7122
8045
  import { add as add2, isBefore } from "date-fns";
7123
- import useSWR7, { SWRConfig } from "swr";
8046
+ import useSWR8, { SWRConfig } from "swr";
7124
8047
  var reducer = (state, action) => {
7125
8048
  switch (action.type) {
7126
8049
  case "LayerContext.setAuth" /* setAuth */:
@@ -7173,7 +8096,7 @@ var LayerProvider = ({
7173
8096
  theme,
7174
8097
  colors
7175
8098
  });
7176
- const { data: auth } = appId !== void 0 && appSecret !== void 0 ? useSWR7(
8099
+ const { data: auth } = appId !== void 0 && appSecret !== void 0 ? useSWR8(
7177
8100
  businessAccessToken === void 0 && appId !== void 0 && appSecret !== void 0 && isBefore(state.auth.expires_at, /* @__PURE__ */ new Date()) && "authenticate",
7178
8101
  Layer.authenticate({
7179
8102
  appId,
@@ -7183,7 +8106,7 @@ var LayerProvider = ({
7183
8106
  }),
7184
8107
  defaultSWRConfig
7185
8108
  ) : { data: void 0 };
7186
- useEffect12(() => {
8109
+ useEffect16(() => {
7187
8110
  if (businessAccessToken) {
7188
8111
  dispatch({
7189
8112
  type: "LayerContext.setAuth" /* setAuth */,
@@ -7208,7 +8131,7 @@ var LayerProvider = ({
7208
8131
  });
7209
8132
  }
7210
8133
  }, [businessAccessToken, auth?.access_token]);
7211
- useSWR7(
8134
+ useSWR8(
7212
8135
  businessId && auth?.access_token && `categories-${businessId}`,
7213
8136
  Layer.getCategories(apiUrl, auth?.access_token, { params: { businessId } }),
7214
8137
  {
@@ -7227,22 +8150,136 @@ var LayerProvider = ({
7227
8150
  type: "LayerContext.setTheme" /* setTheme */,
7228
8151
  payload: { theme: theme2 }
7229
8152
  });
8153
+ const setLightColor = (color) => {
8154
+ setTheme({
8155
+ ...state.theme ?? {},
8156
+ colors: {
8157
+ ...state.theme?.colors ?? {},
8158
+ light: color
8159
+ }
8160
+ });
8161
+ };
8162
+ const setDarkColor = (color) => {
8163
+ setTheme({
8164
+ ...state.theme ?? {},
8165
+ colors: {
8166
+ ...state.theme?.colors ?? {},
8167
+ dark: color
8168
+ }
8169
+ });
8170
+ };
8171
+ const setColors = (colors2) => {
8172
+ setTheme({
8173
+ ...state.theme ?? {},
8174
+ colors: colors2
8175
+ });
8176
+ };
7230
8177
  const getColor = (shade) => {
7231
8178
  if (colors && shade in colors) {
7232
8179
  return colors[shade];
7233
8180
  }
7234
8181
  return;
7235
8182
  };
7236
- return /* @__PURE__ */ React89.createElement(SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ React89.createElement(LayerContext.Provider, { value: { ...state, setTheme, getColor } }, children));
8183
+ return /* @__PURE__ */ React97.createElement(SWRConfig, { value: defaultSWRConfig }, /* @__PURE__ */ React97.createElement(
8184
+ LayerContext.Provider,
8185
+ {
8186
+ value: { ...state, setTheme, getColor, setLightColor, setDarkColor, setColors }
8187
+ },
8188
+ children
8189
+ ));
8190
+ };
8191
+
8192
+ // src/views/AccountingOverview/AccountingOverview.tsx
8193
+ import React100 from "react";
8194
+
8195
+ // src/components/View/View.tsx
8196
+ import React99 from "react";
8197
+
8198
+ // src/components/ViewHeader/ViewHeader.tsx
8199
+ import React98 from "react";
8200
+ var ViewHeader = ({ title, controls }) => {
8201
+ return /* @__PURE__ */ React98.createElement("div", { className: "Layer__view-header" }, /* @__PURE__ */ React98.createElement("div", { className: "Layer__view-header__content" }, /* @__PURE__ */ React98.createElement(Heading, null, title), controls && /* @__PURE__ */ React98.createElement("div", { className: "Layer__view-header__controls" }, controls)));
8202
+ };
8203
+
8204
+ // src/components/View/View.tsx
8205
+ var View6 = ({ title, children, headerControls }) => {
8206
+ const { theme } = useLayerContext();
8207
+ const styles = parseStylesFromThemeConfig(theme);
8208
+ return /* @__PURE__ */ React99.createElement("div", { className: "Layer__view", style: { ...styles } }, /* @__PURE__ */ React99.createElement(ViewHeader, { title, controls: headerControls }), /* @__PURE__ */ React99.createElement("div", { className: "Layer__view-main" }, children));
8209
+ };
8210
+
8211
+ // src/views/AccountingOverview/AccountingOverview.tsx
8212
+ var AccountingOverview = ({
8213
+ title = "Accounting overview"
8214
+ }) => {
8215
+ return /* @__PURE__ */ React100.createElement(ProfitAndLoss, { asContainer: false }, /* @__PURE__ */ React100.createElement(View6, { title, headerControls: /* @__PURE__ */ React100.createElement(ProfitAndLoss.DatePicker, null) }, /* @__PURE__ */ React100.createElement(ProfitAndLoss.Summaries, { actionable: false }), /* @__PURE__ */ React100.createElement(
8216
+ Container,
8217
+ {
8218
+ name: "accounting-overview-profit-and-loss",
8219
+ asWidget: true,
8220
+ elevated: true
8221
+ },
8222
+ /* @__PURE__ */ React100.createElement(Header, null, /* @__PURE__ */ React100.createElement(Heading, { size: "secondary" /* secondary */ }, "Profit & Loss")),
8223
+ /* @__PURE__ */ React100.createElement(ProfitAndLoss.Chart, null)
8224
+ ), /* @__PURE__ */ React100.createElement("div", { className: "accounting-overview-profit-and-loss-charts" }, /* @__PURE__ */ React100.createElement(Container, { name: "accounting-overview-profit-and-loss-chart" }, /* @__PURE__ */ React100.createElement(ProfitAndLoss.DetailedCharts, { scope: "revenue", hideClose: true })), /* @__PURE__ */ React100.createElement(Container, { name: "accounting-overview-profit-and-loss-chart" }, /* @__PURE__ */ React100.createElement(ProfitAndLoss.DetailedCharts, { scope: "expenses", hideClose: true })))));
8225
+ };
8226
+
8227
+ // src/views/BankTransactionsWithLinkedAccounts/BankTransactionsWithLinkedAccounts.tsx
8228
+ import React101 from "react";
8229
+ var BankTransactionsWithLinkedAccounts = ({
8230
+ title = "Bank transactions"
8231
+ }) => {
8232
+ return /* @__PURE__ */ React101.createElement(View6, { title }, /* @__PURE__ */ React101.createElement(LinkedAccounts, { elevated: true }), /* @__PURE__ */ React101.createElement(BankTransactions, { asWidget: true }));
8233
+ };
8234
+
8235
+ // src/views/Reports/Reports.tsx
8236
+ import React102, { useContext as useContext15, useRef as useRef15 } from "react";
8237
+ var Reports = ({ title = "Reports" }) => {
8238
+ const containerRef = useRef15(null);
8239
+ return /* @__PURE__ */ React102.createElement(ProfitAndLoss, { asContainer: false }, /* @__PURE__ */ React102.createElement(View6, { title, headerControls: /* @__PURE__ */ React102.createElement(ProfitAndLoss.DatePicker, null) }, /* @__PURE__ */ React102.createElement(
8240
+ Toggle,
8241
+ {
8242
+ name: "reports-tabs",
8243
+ options: [
8244
+ {
8245
+ value: "profitAndLoss",
8246
+ label: "Profit & loss"
8247
+ },
8248
+ {
8249
+ value: "balanceSheet",
8250
+ label: "Balance sheet",
8251
+ disabled: true
8252
+ }
8253
+ ],
8254
+ selected: "profitAndLoss",
8255
+ onChange: () => null
8256
+ }
8257
+ ), /* @__PURE__ */ React102.createElement(Container, { name: "reports", ref: containerRef }, /* @__PURE__ */ React102.createElement(ReportsPanel, { containerRef }))));
8258
+ };
8259
+ var ReportsPanel = ({ containerRef }) => {
8260
+ const { sidebarScope } = useContext15(ProfitAndLoss.Context);
8261
+ return /* @__PURE__ */ React102.createElement(
8262
+ Panel,
8263
+ {
8264
+ sidebar: /* @__PURE__ */ React102.createElement(ProfitAndLoss.DetailedCharts, null),
8265
+ sidebarIsOpen: Boolean(sidebarScope),
8266
+ parentRef: containerRef
8267
+ },
8268
+ /* @__PURE__ */ React102.createElement(ProfitAndLoss.Table, { asContainer: false })
8269
+ );
7237
8270
  };
7238
8271
  export {
8272
+ AccountingOverview,
7239
8273
  BalanceSheet,
7240
8274
  BankTransactions,
8275
+ BankTransactionsWithLinkedAccounts,
8276
+ ChartOfAccounts,
7241
8277
  Hello,
7242
8278
  LayerProvider,
7243
- LedgerAccounts,
7244
8279
  LinkedAccounts,
7245
8280
  ProfitAndLoss,
7246
- ProfitAndLossView
8281
+ ProfitAndLossView,
8282
+ Reports,
8283
+ useLayerContext
7247
8284
  };
7248
8285
  //# sourceMappingURL=index.js.map