@accounter/client 0.0.8-alpha-20251021225827-178e480c997a9811913e16f85cb94329041b096e → 0.0.8-alpha-20251022130946-0923a77d2ee3f22a60a7f5b1e0623bd3bee88868

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +1 -25
  2. package/dist/assets/index-B2UYAO1O.css +1 -0
  3. package/dist/assets/index-BexxGuN6.js +1224 -0
  4. package/dist/assets/{index.es-CYeQ4a5s.js → index.es-CWwhWGxX.js} +5 -5
  5. package/dist/index.html +2 -2
  6. package/package.json +1 -1
  7. package/src/components/business-transactions/business-extended-info.tsx +15 -13
  8. package/src/components/business-transactions/business-transactions-single.tsx +3 -3
  9. package/src/components/business-transactions/index.tsx +1 -12
  10. package/src/components/business-trips/business-trip.tsx +3 -3
  11. package/src/components/charges/cells/business-trip.tsx +8 -6
  12. package/src/components/charges/cells/counterparty.tsx +5 -7
  13. package/src/components/common/accounter-table.tsx +5 -6
  14. package/src/components/common/business-trip-report/parts/core-expense-row.tsx +9 -11
  15. package/src/components/common/business-trip-report/parts/uncategorized-transactions.tsx +13 -11
  16. package/src/components/common/buttons/button-with-label.tsx +41 -0
  17. package/src/components/common/buttons/button.tsx +44 -0
  18. package/src/components/common/buttons/index.ts +2 -0
  19. package/src/components/common/buttons/logout-button.tsx +6 -7
  20. package/src/components/common/documents-to-charge-matcher/selection-handler/index.tsx +2 -4
  21. package/src/components/common/documents-to-charge-matcher/selection-handler/wide-filtered-selection.tsx +7 -5
  22. package/src/components/common/forms/edit-document.tsx +10 -23
  23. package/src/components/common/new-documents-list.tsx +8 -10
  24. package/src/components/documents-table/cells/creditor.tsx +4 -11
  25. package/src/components/documents-table/cells/debtor.tsx +4 -11
  26. package/src/components/layout/dashboard-layout.tsx +0 -4
  27. package/src/components/layout/sidelinks.tsx +27 -28
  28. package/src/components/ledger-table/counterparty-cell.tsx +13 -19
  29. package/src/components/login-page.tsx +1 -2
  30. package/src/components/reports/corporate-tax-ruling-compliance-report/index.tsx +3 -3
  31. package/src/components/reports/profit-and-loss-report/index.tsx +3 -3
  32. package/src/components/reports/tax-report/index.tsx +3 -3
  33. package/src/components/screens/businesses/business.tsx +9 -21
  34. package/src/components/screens/charges/charge.tsx +9 -22
  35. package/src/components/transactions-table/cells/counterparty.tsx +2 -9
  36. package/src/components/transactions-table/cells-legacy/counterparty.tsx +2 -9
  37. package/src/gql/graphql.ts +4842 -1554
  38. package/src/index.tsx +22 -4
  39. package/src/providers/auth-guard.tsx +23 -14
  40. package/src/providers/index.tsx +2 -7
  41. package/src/providers/urql.tsx +12 -7
  42. package/src/providers/user-provider.tsx +2 -3
  43. package/dist/assets/Checkbox-CxedbJAl.js +0 -6
  44. package/dist/assets/Progress-D5SuJtCd.js +0 -1
  45. package/dist/assets/Typography-BQFz-z7L.js +0 -1
  46. package/dist/assets/accordion-COWOBKuq.js +0 -1
  47. package/dist/assets/accountant-approvals-Bd2y8us_.js +0 -1
  48. package/dist/assets/all-charges-SWBnaZu7.js +0 -1
  49. package/dist/assets/arrow-up-down-dZmrBLse.js +0 -6
  50. package/dist/assets/business--GVVfDEa.js +0 -37
  51. package/dist/assets/business-transactions-single-BsbkUf_H.js +0 -1
  52. package/dist/assets/business-trip-ByXPVXdG.js +0 -1
  53. package/dist/assets/charges-filters-D43UbXob.js +0 -1
  54. package/dist/assets/charges-ledger-validation-D0uMH_JE.js +0 -1
  55. package/dist/assets/chart-ClU1KbWe.js +0 -74
  56. package/dist/assets/data-table-pagination-D9Y0_Tn8.js +0 -11
  57. package/dist/assets/editable-business-trip-DhqOQBPa.js +0 -16
  58. package/dist/assets/graphql-document-dedupe-fragments-ByT8-wlV.js +0 -1
  59. package/dist/assets/index-1U6rQgQe.js +0 -6
  60. package/dist/assets/index-3-AKn8tg.js +0 -1
  61. package/dist/assets/index-91A2PLZ6.js +0 -137
  62. package/dist/assets/index-BBHuCWRn.js +0 -1
  63. package/dist/assets/index-BPNuFFtx.js +0 -1
  64. package/dist/assets/index-BXqHnRVY.js +0 -1
  65. package/dist/assets/index-BciOH8FS.js +0 -1
  66. package/dist/assets/index-BjHuUHDO.js +0 -1
  67. package/dist/assets/index-BxKmoNQd.js +0 -1
  68. package/dist/assets/index-C3bqiFIv.js +0 -2
  69. package/dist/assets/index-C5MeepK_.js +0 -11
  70. package/dist/assets/index-CAwm68Mg.js +0 -1
  71. package/dist/assets/index-CJ8OGXxv.js +0 -1
  72. package/dist/assets/index-CJyY-qF6.js +0 -1
  73. package/dist/assets/index-CMYnx46_.js +0 -6
  74. package/dist/assets/index-CNrwxUZ7.js +0 -1
  75. package/dist/assets/index-CvV5z5r9.js +0 -876
  76. package/dist/assets/index-D08H2GXq.js +0 -17
  77. package/dist/assets/index-GFsPY1p4.js +0 -2
  78. package/dist/assets/index-KwNwThNu.js +0 -1
  79. package/dist/assets/index-YA8IBFyB.js +0 -1
  80. package/dist/assets/index-ZpyI3qxW.js +0 -24
  81. package/dist/assets/index-gdTXrWXt.css +0 -1
  82. package/dist/assets/index-ytnIEraq.js +0 -9
  83. package/dist/assets/issue-document-CdikNnO2.js +0 -1
  84. package/dist/assets/login-page-effgZS3V.js +0 -1
  85. package/dist/assets/missing-info-charges-CnPFTzoZ.js +0 -1
  86. package/dist/assets/page-not-found-D8YlgDOm.js +0 -1
  87. package/dist/assets/pencil-mxW0-tGM.js +0 -6
  88. package/dist/assets/report-commentary-row-DCozKgVE.js +0 -1
  89. package/dist/assets/save-CHlytUqu.js +0 -11
  90. package/dist/assets/sequential-CAnleQny.js +0 -1
  91. package/dist/assets/similar-charges-by-business-modal-Dzbspk_r.js +0 -1
  92. package/dist/assets/sub-Cp_PhKiD.js +0 -1
  93. package/dist/assets/subMonths-DCj_iXAn.js +0 -1
  94. package/src/components/error-boundary.tsx +0 -189
  95. package/src/components/layout/breadcrumbs.tsx +0 -77
  96. package/src/components/layout/document-title.tsx +0 -31
  97. package/src/components/layout/navigation-progress.tsx +0 -52
  98. package/src/components/layout/page-skeleton.tsx +0 -49
  99. package/src/providers/urql-client.ts +0 -86
  100. package/src/router/config.tsx +0 -534
  101. package/src/router/layouts/dashboard-layout.tsx +0 -20
  102. package/src/router/layouts/root-layout.tsx +0 -69
  103. package/src/router/loaders/auth-loader.ts +0 -32
  104. package/src/router/loaders/business-loader.ts +0 -25
  105. package/src/router/loaders/charge-loader.ts +0 -25
  106. package/src/router/loaders/index.ts +0 -17
  107. package/src/router/routes.ts +0 -88
  108. package/src/router/types.ts +0 -62
package/dist/index.html CHANGED
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" href="/icons/accounter-logo.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Accounter</title>
8
- <script type="module" crossorigin src="/assets/index-CvV5z5r9.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-gdTXrWXt.css">
8
+ <script type="module" crossorigin src="/assets/index-BexxGuN6.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-B2UYAO1O.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accounter/client",
3
- "version": "0.0.8-alpha-20251021225827-178e480c997a9811913e16f85cb94329041b096e",
3
+ "version": "0.0.8-alpha-20251022130946-0923a77d2ee3f22a60a7f5b1e0623bd3bee88868",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -1,9 +1,8 @@
1
1
  import { useState, type ReactElement } from 'react';
2
2
  import { format } from 'date-fns';
3
3
  import { ChevronsLeftRightEllipsis, ChevronsRightLeft } from 'lucide-react';
4
- import { Link } from 'react-router-dom';
5
4
  import { useQuery } from 'urql';
6
- import { Mark, Table, Tooltip } from '@mantine/core';
5
+ import { Mark, NavLink, Table, Tooltip } from '@mantine/core';
7
6
  import {
8
7
  BusinessTransactionsInfoDocument,
9
8
  Currency,
@@ -15,7 +14,6 @@ import { AccounterLoader } from '../common/index.js';
15
14
  import { getChargeHref } from '../screens/charges/charge.js';
16
15
  import { Button } from '../ui/button.js';
17
16
  import { DownloadCSV } from './download-csv.js';
18
- import { getBusinessTransactionsHref } from './index.js';
19
17
 
20
18
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- used by codegen
21
19
  /* GraphQL */ `
@@ -235,15 +233,17 @@ export function BusinessExtendedInfo({ businessID, filter }: Props): ReactElemen
235
233
  }}
236
234
  >
237
235
  <td>
238
- <Link
239
- to={getBusinessTransactionsHref({ businessIDs: [row.business.id] })}
236
+ <a
237
+ href={`/businesses/${row.business.id}/transactions`}
240
238
  target="_blank"
241
239
  rel="noreferrer"
242
240
  onClick={event => event.stopPropagation()}
243
- className="inline-flex items-center font-semibold"
244
241
  >
245
- {row.business.name}
246
- </Link>
242
+ <NavLink
243
+ label={row.business.name}
244
+ className="[&>*>.mantine-NavLink-label]:font-semibold"
245
+ />
246
+ </a>
247
247
  </td>
248
248
  <td>{row.invoiceDate ? format(new Date(row.invoiceDate), 'dd/MM/yy') : null}</td>
249
249
  <td style={{ whiteSpace: 'nowrap' }}>
@@ -273,15 +273,17 @@ export function BusinessExtendedInfo({ businessID, filter }: Props): ReactElemen
273
273
  <td>{row.details}</td>
274
274
  <td>
275
275
  {row.counterAccount && (
276
- <Link
277
- to={getBusinessTransactionsHref({ businessIDs: [row.counterAccount.id] })}
276
+ <a
277
+ href={`/businesses/${row.counterAccount?.id}/transactions`}
278
278
  target="_blank"
279
279
  rel="noreferrer"
280
280
  onClick={event => event.stopPropagation()}
281
- className="inline-flex items-center font-semibold"
282
281
  >
283
- {row.counterAccount.name}
284
- </Link>
282
+ <NavLink
283
+ label={row.counterAccount?.name}
284
+ className="[&>*>.mantine-NavLink-label]:font-semibold"
285
+ />
286
+ </a>
285
287
  )}
286
288
  </td>
287
289
  <td />
@@ -1,5 +1,5 @@
1
1
  import { useContext, useEffect, useMemo, useState, type ReactElement, type ReactNode } from 'react';
2
- import { useParams } from 'react-router-dom';
2
+ import { useMatch } from 'react-router-dom';
3
3
  import { useQuery } from 'urql';
4
4
  import { Mark } from '@mantine/core';
5
5
  import {
@@ -19,10 +19,10 @@ type Props = {
19
19
  };
20
20
 
21
21
  export const BusinessTransactionsSingle = ({ businessId }: Props): ReactElement => {
22
- const { businessId: businessIdFromUrl } = useParams<{ businessId: string }>();
22
+ const match = useMatch('businesses/:businessId/transactions');
23
23
  const { get } = useUrlQuery();
24
24
  const { setFiltersContext } = useContext(FiltersContext);
25
- const id = businessId || businessIdFromUrl;
25
+ const id = businessId || match?.params.businessId;
26
26
  const [filter, setFilter] = useState<BusinessTransactionsFilter>(
27
27
  get('transactionsFilters')
28
28
  ? {
@@ -72,24 +72,13 @@ import {
72
72
  export function getBusinessTransactionsHref(filter?: BusinessTransactionsFilter | null): string {
73
73
  const params = new URLSearchParams();
74
74
 
75
- let businessId: string | undefined = undefined;
76
- let adjustedFilter = filter;
77
- if (filter?.businessIDs && filter.businessIDs.length === 1) {
78
- const { businessIDs, ...rest } = filter;
79
- businessId = businessIDs[0];
80
- adjustedFilter = rest;
81
- }
82
-
83
- const transactionsFilters = encodeTransactionsFilters(adjustedFilter);
75
+ const transactionsFilters = encodeTransactionsFilters(filter);
84
76
  if (transactionsFilters) {
85
77
  // Add it as a single encoded parameter
86
78
  params.append('transactionsFilters', transactionsFilters);
87
79
  }
88
80
 
89
81
  const queryParams = params.size > 0 ? `?${params}` : '';
90
- if (businessId) {
91
- return `/businesses/${businessId}/transactions${queryParams}`;
92
- }
93
82
  return `/businesses/transactions${queryParams}`;
94
83
  }
95
84
 
@@ -1,5 +1,5 @@
1
1
  import { useContext, useEffect, type ReactElement } from 'react';
2
- import { useParams } from 'react-router-dom';
2
+ import { useMatch } from 'react-router-dom';
3
3
  import { useQuery } from 'urql';
4
4
  import { Container } from '@mantine/core';
5
5
  import { BusinessTripScreenDocument } from '../../gql/graphql.js';
@@ -26,9 +26,9 @@ type Props = {
26
26
  };
27
27
 
28
28
  export const BusinessTrip = ({ businessTripId }: Props): ReactElement => {
29
- const { businessTripId: businessTripIdFromUrl } = useParams<{ businessTripId: string }>();
29
+ const match = useMatch('business-trips/:businessTripId');
30
30
  const { setFiltersContext } = useContext(FiltersContext);
31
- const id = businessTripId ?? businessTripIdFromUrl ?? '';
31
+ const id = businessTripId ?? match?.params.businessTripId ?? '';
32
32
  const [{ data, fetching }] = useQuery({
33
33
  query: BusinessTripScreenDocument,
34
34
  variables: {
@@ -1,5 +1,5 @@
1
1
  import { type ReactElement } from 'react';
2
- import { Link } from 'react-router-dom';
2
+ import { NavLink } from '@mantine/core';
3
3
  import { ChargesTableBusinessTripFieldsFragmentDoc } from '../../../gql/graphql.js';
4
4
  import { getFragmentData, type FragmentType } from '../../../gql/index.js';
5
5
 
@@ -29,15 +29,17 @@ export const BusinessTrip = ({ data }: Props): ReactElement => {
29
29
 
30
30
  return (
31
31
  <td>
32
- <Link
33
- to={`/business-trips/${charge.businessTrip?.id}`}
32
+ <a
33
+ href={`/business-trips/${charge.businessTrip?.id}`}
34
34
  target="_blank"
35
35
  rel="noreferrer"
36
36
  onClick={event => event.stopPropagation()}
37
- className="inline-flex items-center font-semibold"
38
37
  >
39
- {charge.businessTrip?.name}
40
- </Link>
38
+ <NavLink
39
+ label={charge.businessTrip?.name}
40
+ className="[&>*>.mantine-NavLink-label]:font-semibold"
41
+ />
42
+ </a>
41
43
  </td>
42
44
  );
43
45
  };
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useMemo, type ReactElement } from 'react';
2
- import { Link } from 'react-router-dom';
3
- import { Indicator } from '@mantine/core';
2
+ import { Indicator, NavLink } from '@mantine/core';
4
3
  import {
5
4
  ChargesTableEntityFieldsFragmentDoc,
6
5
  MissingChargeInfo,
@@ -82,15 +81,14 @@ export const Counterparty = ({ data }: Props): ReactElement => {
82
81
  <div className="flex flex-wrap">
83
82
  <Indicator inline size={12} disabled={!isError} color="red" zIndex="auto">
84
83
  {!isError && id && (
85
- <Link
86
- to={getHref(id)}
84
+ <a
85
+ href={getHref(id)}
87
86
  target="_blank"
88
87
  rel="noreferrer"
89
88
  onClick={event => event.stopPropagation()}
90
- className="inline-flex items-center font-semibold"
91
89
  >
92
- {name}
93
- </Link>
90
+ <NavLink label={name} className="[&>*>.mantine-NavLink-label]:font-semibold" />
91
+ </a>
94
92
  )}
95
93
  {isError && name}
96
94
  </Indicator>
@@ -1,6 +1,6 @@
1
1
  import { useState, type ReactElement, type ReactNode } from 'react';
2
- import { Button } from '@/components/ui/button.js';
3
2
  import { Pagination, Paper, Table, type PaginationProps } from '@mantine/core';
3
+ import { Button } from './index.js';
4
4
 
5
5
  export interface AccounterTableProps<T, U> {
6
6
  highlightOnHover?: boolean;
@@ -47,9 +47,7 @@ export function AccounterTableRow<T, U>(props: AccountTableRow<T, U>): ReactElem
47
47
  {moreInfoValue === null ? (
48
48
  <p>No Data Related</p>
49
49
  ) : (
50
- <Button onClick={(): void => setOpened(!opened)} className="ml-auto">
51
- More Info
52
- </Button>
50
+ <Button title="More Info" onClick={(): void => setOpened(!opened)} />
53
51
  )}
54
52
  </td>
55
53
  )}
@@ -75,14 +73,15 @@ export function AccounterTable<T, U>(props: AccounterTableProps<T, U>): ReactNod
75
73
  <div className="flex flex-row justify-end w-full">
76
74
  {props.pagination && <Pagination className="flex-auto" {...props.pagination} />}
77
75
  {props.showButton === true ? (
78
- <Button
76
+ <button
77
+ className="inline-flex text-white bg-indigo-500 border-0 py-1.5 px-3 focus:outline-hidden hover:bg-indigo-600 rounded-sm text-sm"
79
78
  type="button"
80
79
  onClick={(): void => {
81
80
  setIsShowAll(prev => !prev);
82
81
  }}
83
82
  >
84
83
  {isShowAll ? 'Hide All' : 'Show All'}
85
- </Button>
84
+ </button>
86
85
  ) : null}
87
86
  </div>
88
87
  <Table striped={props.striped} highlightOnHover={props.highlightOnHover}>
@@ -1,10 +1,9 @@
1
1
  import { useEffect, useState, type ReactElement } from 'react';
2
2
  import { format } from 'date-fns';
3
3
  import { Controller, type Control } from 'react-hook-form';
4
- import { Link } from 'react-router-dom';
5
4
  import { toast } from 'sonner';
6
5
  import { useQuery } from 'urql';
7
- import { Select, Text } from '@mantine/core';
6
+ import { NavLink, Select, Text } from '@mantine/core';
8
7
  import { DatePickerInput } from '@mantine/dates';
9
8
  import {
10
9
  AttendeesByBusinessTripDocument,
@@ -237,16 +236,15 @@ export const CoreExpenseRow = ({
237
236
  <td>
238
237
  <div className="flex flex-col gap-2">
239
238
  {linkedChargeIds.map(id => (
240
- <Link
239
+ <NavLink
241
240
  key={id}
242
- to={getChargeHref(id)}
243
- target="_blank"
244
- rel="noreferrer"
245
- onClick={event => event.stopPropagation()}
246
- className="inline-flex items-center font-semibold"
247
- >
248
- To Charge
249
- </Link>
241
+ label="To Charge"
242
+ className="[&>*>.mantine-NavLink-label]:font-semibold"
243
+ onClick={(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
244
+ event.stopPropagation();
245
+ window.open(getChargeHref(id), '_blank', 'noreferrer');
246
+ }}
247
+ />
250
248
  ))}
251
249
  </div>
252
250
  </td>
@@ -1,7 +1,6 @@
1
1
  import type { ReactElement } from 'react';
2
2
  import { AlertCircle } from 'lucide-react';
3
- import { Link } from 'react-router-dom';
4
- import { Popover, Table, Text } from '@mantine/core';
3
+ import { NavLink, Popover, Table, Text } from '@mantine/core';
5
4
  import { useDisclosure } from '@mantine/hooks';
6
5
  import {
7
6
  BusinessTripUncategorizedTransactionsFieldsFragmentDoc,
@@ -93,15 +92,18 @@ export const UncategorizedTransactions = ({ data, onChange }: Props): ReactEleme
93
92
  <DebitDate data={uncategorizedTransaction.transaction} />
94
93
  <Amount data={uncategorizedTransaction} />
95
94
  <td>
96
- <Link
97
- to={getChargeHref(uncategorizedTransaction.transaction.chargeId)}
98
- target="_blank"
99
- rel="noreferrer"
100
- onClick={event => event.stopPropagation()}
101
- className="inline-flex items-center font-semibold"
102
- >
103
- To Charge
104
- </Link>
95
+ <NavLink
96
+ label="To Charge"
97
+ className="[&>*>.mantine-NavLink-label]:font-semibold"
98
+ onClick={(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
99
+ event.stopPropagation();
100
+ window.open(
101
+ getChargeHref(uncategorizedTransaction.transaction.chargeId),
102
+ '_blank',
103
+ 'noreferrer',
104
+ );
105
+ }}
106
+ />
105
107
  </td>
106
108
  <Account data={uncategorizedTransaction.transaction} />
107
109
  <Description data={uncategorizedTransaction.transaction} />
@@ -0,0 +1,41 @@
1
+ import type { CSSProperties, MouseEventHandler, ReactElement } from 'react';
2
+
3
+ export interface ButtonWithLabelProps {
4
+ onClick?: MouseEventHandler<HTMLButtonElement>;
5
+ type?: 'submit' | 'button';
6
+ style?: CSSProperties;
7
+ target?: string;
8
+ rel?: string;
9
+ title?: string;
10
+ url?: string;
11
+ textLabel?: string;
12
+ }
13
+
14
+ export const ButtonWithLabel = ({
15
+ title,
16
+ url,
17
+ style,
18
+ target,
19
+ textLabel,
20
+ rel,
21
+ type = 'button',
22
+ onClick,
23
+ }: ButtonWithLabelProps): ReactElement => {
24
+ return (
25
+ <div>
26
+ <label className="text-sm font-medium text-gray-700">{textLabel}</label>
27
+ <div>
28
+ <button
29
+ style={style}
30
+ type={type}
31
+ onClick={onClick}
32
+ className="bg-gray-100 border focus:ring-2 focus:ring-indigo-200 focus:bg-transparent hover:bg-indigo-500 hover:text-white text-base outline-hidden text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out sm:text-sm rounded-md"
33
+ >
34
+ <a rel={rel} target={target} href={url} type={type}>
35
+ {title}
36
+ </a>
37
+ </button>
38
+ </div>
39
+ </div>
40
+ );
41
+ };
@@ -0,0 +1,44 @@
1
+ import type {
2
+ ButtonHTMLAttributes,
3
+ CSSProperties,
4
+ DetailedHTMLProps,
5
+ MouseEventHandler,
6
+ ReactElement,
7
+ } from 'react';
8
+
9
+ export interface Props
10
+ extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
11
+ onClick?: MouseEventHandler<HTMLButtonElement>;
12
+ herf?: string;
13
+ type?: 'submit' | 'button';
14
+ style?: CSSProperties;
15
+ target?: string;
16
+ rel?: string;
17
+ title?: string;
18
+ url?: string;
19
+ }
20
+
21
+ export const Button = ({
22
+ title,
23
+ herf,
24
+ style,
25
+ target,
26
+ rel,
27
+ type = 'button',
28
+ onClick,
29
+ ...props
30
+ }: Props): ReactElement => {
31
+ return (
32
+ <button
33
+ style={style}
34
+ type={type}
35
+ onClick={onClick}
36
+ className="cursor: pointer text-align: center flex ml-auto text-white bg-indigo-500 border-0 py-1.5 px-3 focus:outline-hidden hover:bg-indigo-600 rounded-sm;"
37
+ {...props}
38
+ >
39
+ <a rel={rel} target={target} href={herf} type={type}>
40
+ {title}
41
+ </a>
42
+ </button>
43
+ );
44
+ };
@@ -1,3 +1,5 @@
1
+ export * from './button.js';
2
+ export * from './button-with-label.js';
1
3
  export * from './charge-navigate-button.js';
2
4
  export * from './close-document-button.js';
3
5
  export * from './confirm-mini-button.js';
@@ -1,20 +1,19 @@
1
- import { useContext, type ReactElement } from 'react';
1
+ import { useCallback, useContext, type ReactElement } from 'react';
2
2
  import { useNavigate } from 'react-router-dom';
3
3
  import { AuthContext } from '../../../providers/auth-guard.js';
4
- import { ROUTES } from '../../../router/routes.js';
5
4
  import { Button } from '../../ui/button.js';
6
5
 
7
6
  export function LogoutButton(): ReactElement {
8
7
  const navigate = useNavigate();
9
8
  const { authService } = useContext(AuthContext);
10
9
 
11
- const handleLogout = async (): Promise<void> => {
12
- await authService.logout();
13
- navigate(ROUTES.LOGIN);
14
- };
10
+ const onLogout = useCallback(() => {
11
+ authService.logout();
12
+ navigate('/login');
13
+ }, [navigate, authService]);
15
14
 
16
15
  return (
17
- <Button variant="ghost" onClick={handleLogout}>
16
+ <Button variant="ghost" onClick={onLogout}>
18
17
  Log out
19
18
  </Button>
20
19
  );
@@ -1,5 +1,4 @@
1
1
  import { useMemo, useState, type ReactElement } from 'react';
2
- import { Button } from '@/components/ui/button.js';
3
2
  import {
4
3
  ChargeToMatchDocumentsFieldsFragmentDoc,
5
4
  DocumentsToMatchFieldsFragmentDoc,
@@ -10,6 +9,7 @@ import { getFragmentData, type FragmentType } from '../../../../gql/index.js';
10
9
  import { useUpdateDocument } from '../../../../hooks/use-update-document.js';
11
10
  import { FormLabel } from '../../../ui/form.js';
12
11
  import { Switch } from '../../../ui/switch.js';
12
+ import { Button } from '../../index.js';
13
13
  import { StrictFilteredSelection } from './strict-filtered-selection.js';
14
14
  import { WideFilteredSelection } from './wide-filtered-selection.js';
15
15
 
@@ -165,9 +165,7 @@ export function SelectionHandler({ chargeProps, documentsProps, onDone }: Props)
165
165
  <Switch checked={filterSuggestions} onCheckedChange={setFilterSuggestions} />
166
166
  </div>
167
167
  )}
168
- <Button disabled={selectedDocuments.length === 0} onClick={onExecuteMatch}>
169
- Accept
170
- </Button>
168
+ <Button title="Accept" disabled={selectedDocuments.length === 0} onClick={onExecuteMatch} />
171
169
  </div>
172
170
  <div>
173
171
  {filterSuggestions ? (
@@ -1,11 +1,10 @@
1
1
  import { useState, type ReactElement } from 'react';
2
- import { Button } from '@/components/ui/button.js';
3
2
  import { Image } from '@mantine/core';
4
3
  import {
5
4
  type ChargeToMatchDocumentsFieldsFragment,
6
5
  type DocumentsToMatchFieldsFragment,
7
6
  } from '../../../../gql/graphql.js';
8
- import { AccounterTable, PopUpModal } from '../../index.js';
7
+ import { AccounterTable, Button, PopUpModal } from '../../index.js';
9
8
 
10
9
  interface Props {
11
10
  documents: Exclude<
@@ -54,9 +53,12 @@ export function WideFilteredSelection({
54
53
  title: 'File',
55
54
  value: doc =>
56
55
  doc.file && (
57
- <a href={doc.file?.toString()} target="_blank" rel="noreferrer">
58
- <Button>Open Link</Button>
59
- </a>
56
+ <Button
57
+ target="_blank"
58
+ rel="noreferrer"
59
+ herf={doc.file?.toString()}
60
+ title="Open Link"
61
+ />
60
62
  ),
61
63
  },
62
64
  { title: 'Date', value: doc => ('date' in doc ? doc.date : null) },
@@ -1,15 +1,12 @@
1
1
  import { useEffect, useState, type ReactElement } from 'react';
2
2
  import { useForm, type SubmitHandler } from 'react-hook-form';
3
- import { Link } from 'react-router-dom';
4
3
  import { useQuery } from 'urql';
5
- import { Button } from '@/components/ui/button.js';
6
- import { Label } from '@/components/ui/label.js';
7
4
  import { Drawer, Image, Loader } from '@mantine/core';
8
5
  import { EditDocumentDocument, type UpdateDocumentFieldsInput } from '../../../gql/graphql.js';
9
6
  import { relevantDataPicker, type MakeBoolean } from '../../../helpers/form.js';
10
7
  import { useUpdateDocument } from '../../../hooks/use-update-document.js';
11
8
  import { Form } from '../../ui/form.js';
12
- import { ImageMagnifier, SimpleGrid } from '../index.js';
9
+ import { ButtonWithLabel, ImageMagnifier, SimpleGrid } from '../index.js';
13
10
  import { ModifyDocumentFields } from './modify-document-fields.js';
14
11
 
15
12
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- used by codegen
@@ -109,31 +106,21 @@ export const EditDocument = ({ documentId, onDone, onChange }: Props): ReactElem
109
106
  <form onSubmit={handleSubmit(onSubmit)}>
110
107
  <SimpleGrid cols={4}>
111
108
  <ModifyDocumentFields document={document} formManager={formManager} />
112
-
113
- <div className="space-y-2">
114
- <Label htmlFor="file">File</Label>
115
- <Link
116
- to={document?.file?.toString() || ''}
117
- target="_blank"
118
- rel="noreferrer"
119
- className="flex flex-col items-center justify-center mt-5"
120
- >
121
- <Button variant="outline" className="w-full mb-2">
122
- Open File
123
- </Button>
124
- </Link>
125
- </div>
109
+ <ButtonWithLabel
110
+ target="_blank"
111
+ textLabel="File"
112
+ url={document?.file?.toString()}
113
+ title="Open Link"
114
+ />
126
115
  </SimpleGrid>
127
116
  <div className="flex justify-center mt-5">
128
- <Button
117
+ <button
129
118
  type="submit"
130
- variant="default"
131
- // className="inline-flex cursor-pointer justify-center py-2 px-4 w-2/12 mr-5 border border-transparent shadow-xs text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
132
- onClick={onDone}
119
+ className="inline-flex cursor-pointer justify-center py-2 px-4 w-2/12 border border-transparent shadow-xs text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-hidden focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
133
120
  disabled={fetching || Object.keys(dirtyFields).length === 0}
134
121
  >
135
122
  Save
136
- </Button>
123
+ </button>
137
124
  </div>
138
125
  </form>
139
126
  </Form>
@@ -1,5 +1,5 @@
1
1
  import type { ReactElement } from 'react';
2
- import { Link } from 'react-router-dom';
2
+ import { NavLink } from '@mantine/core';
3
3
  import { NewFetchedDocumentFieldsFragmentDoc } from '../../gql/graphql.js';
4
4
  import { getFragmentData, type FragmentType } from '../../gql/index.js';
5
5
  import { getChargeHref } from '../screens/charges/charge.js';
@@ -32,16 +32,14 @@ export const NewDocumentsList = ({ data }: Props): ReactElement => {
32
32
  {documents
33
33
  .filter(({ charge }) => charge)
34
34
  .map(doc => (
35
- <Link
35
+ <NavLink
36
36
  key={doc.id}
37
- to={getChargeHref(doc.charge!.id)}
38
- target="_blank"
39
- rel="noreferrer"
40
- onClick={event => event.stopPropagation()}
41
- className="inline-flex items-center font-semibold"
42
- >
43
- {`${doc.charge!.counterparty?.name ?? 'Unknown'} - ${doc.charge!.userDescription}`}
44
- </Link>
37
+ label={`${doc.charge!.counterparty?.name ?? 'Unknown'} - ${doc.charge!.userDescription}`}
38
+ onClick={(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
39
+ event.stopPropagation();
40
+ window.open(getChargeHref(doc.charge!.id), '_blank', 'noreferrer');
41
+ }}
42
+ />
45
43
  ))}
46
44
  </div>
47
45
  );
@@ -1,10 +1,9 @@
1
1
  import { useCallback, useMemo, useState, type ReactElement } from 'react';
2
- import { Link } from 'react-router-dom';
3
2
  import { DocumentType } from '@/gql/graphql.js';
4
3
  import { useGetBusinesses } from '@/hooks/use-get-businesses.js';
5
4
  import { useUpdateDocument } from '@/hooks/use-update-document.js';
6
5
  import { useUrlQuery } from '@/hooks/use-url-query.js';
7
- import { Indicator } from '@mantine/core';
6
+ import { Indicator, NavLink } from '@mantine/core';
8
7
  import { getBusinessHref } from '../../charges/helpers.js';
9
8
  import { ConfirmMiniButton, InsertBusiness, SelectWithSearch } from '../../common/index.js';
10
9
  import type { DocumentsTableRowType } from '../columns.js';
@@ -105,15 +104,9 @@ export const Creditor = ({ document, onChange }: Props): ReactElement => {
105
104
  <Indicator inline size={12} disabled={!isError} color="red" zIndex="auto">
106
105
  {shouldHaveCreditor &&
107
106
  (id ? (
108
- <Link
109
- to={getHref(id)}
110
- target="_blank"
111
- rel="noreferrer"
112
- onClick={event => event.stopPropagation()}
113
- className="inline-flex items-center font-semibold"
114
- >
115
- {name}
116
- </Link>
107
+ <a href={getHref(id)} target="_blank" rel="noreferrer">
108
+ <NavLink label={name} className="[&>*>.mantine-NavLink-label]:font-semibold" />
109
+ </a>
117
110
  ) : (
118
111
  <SelectWithSearch
119
112
  options={selectableBusinesses}