@accounter/client 0.0.8-alpha-20251021225827-178e480c997a9811913e16f85cb94329041b096e → 0.0.8-alpha-20251022034712-a30a030f5a83f0dff0ee9fa8ccd0ebdaf7986647

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 (107) 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/index.tsx +22 -4
  38. package/src/providers/auth-guard.tsx +23 -14
  39. package/src/providers/index.tsx +2 -7
  40. package/src/providers/urql.tsx +12 -7
  41. package/src/providers/user-provider.tsx +2 -3
  42. package/dist/assets/Checkbox-CxedbJAl.js +0 -6
  43. package/dist/assets/Progress-D5SuJtCd.js +0 -1
  44. package/dist/assets/Typography-BQFz-z7L.js +0 -1
  45. package/dist/assets/accordion-COWOBKuq.js +0 -1
  46. package/dist/assets/accountant-approvals-Bd2y8us_.js +0 -1
  47. package/dist/assets/all-charges-SWBnaZu7.js +0 -1
  48. package/dist/assets/arrow-up-down-dZmrBLse.js +0 -6
  49. package/dist/assets/business--GVVfDEa.js +0 -37
  50. package/dist/assets/business-transactions-single-BsbkUf_H.js +0 -1
  51. package/dist/assets/business-trip-ByXPVXdG.js +0 -1
  52. package/dist/assets/charges-filters-D43UbXob.js +0 -1
  53. package/dist/assets/charges-ledger-validation-D0uMH_JE.js +0 -1
  54. package/dist/assets/chart-ClU1KbWe.js +0 -74
  55. package/dist/assets/data-table-pagination-D9Y0_Tn8.js +0 -11
  56. package/dist/assets/editable-business-trip-DhqOQBPa.js +0 -16
  57. package/dist/assets/graphql-document-dedupe-fragments-ByT8-wlV.js +0 -1
  58. package/dist/assets/index-1U6rQgQe.js +0 -6
  59. package/dist/assets/index-3-AKn8tg.js +0 -1
  60. package/dist/assets/index-91A2PLZ6.js +0 -137
  61. package/dist/assets/index-BBHuCWRn.js +0 -1
  62. package/dist/assets/index-BPNuFFtx.js +0 -1
  63. package/dist/assets/index-BXqHnRVY.js +0 -1
  64. package/dist/assets/index-BciOH8FS.js +0 -1
  65. package/dist/assets/index-BjHuUHDO.js +0 -1
  66. package/dist/assets/index-BxKmoNQd.js +0 -1
  67. package/dist/assets/index-C3bqiFIv.js +0 -2
  68. package/dist/assets/index-C5MeepK_.js +0 -11
  69. package/dist/assets/index-CAwm68Mg.js +0 -1
  70. package/dist/assets/index-CJ8OGXxv.js +0 -1
  71. package/dist/assets/index-CJyY-qF6.js +0 -1
  72. package/dist/assets/index-CMYnx46_.js +0 -6
  73. package/dist/assets/index-CNrwxUZ7.js +0 -1
  74. package/dist/assets/index-CvV5z5r9.js +0 -876
  75. package/dist/assets/index-D08H2GXq.js +0 -17
  76. package/dist/assets/index-GFsPY1p4.js +0 -2
  77. package/dist/assets/index-KwNwThNu.js +0 -1
  78. package/dist/assets/index-YA8IBFyB.js +0 -1
  79. package/dist/assets/index-ZpyI3qxW.js +0 -24
  80. package/dist/assets/index-gdTXrWXt.css +0 -1
  81. package/dist/assets/index-ytnIEraq.js +0 -9
  82. package/dist/assets/issue-document-CdikNnO2.js +0 -1
  83. package/dist/assets/login-page-effgZS3V.js +0 -1
  84. package/dist/assets/missing-info-charges-CnPFTzoZ.js +0 -1
  85. package/dist/assets/page-not-found-D8YlgDOm.js +0 -1
  86. package/dist/assets/pencil-mxW0-tGM.js +0 -6
  87. package/dist/assets/report-commentary-row-DCozKgVE.js +0 -1
  88. package/dist/assets/save-CHlytUqu.js +0 -11
  89. package/dist/assets/sequential-CAnleQny.js +0 -1
  90. package/dist/assets/similar-charges-by-business-modal-Dzbspk_r.js +0 -1
  91. package/dist/assets/sub-Cp_PhKiD.js +0 -1
  92. package/dist/assets/subMonths-DCj_iXAn.js +0 -1
  93. package/src/components/error-boundary.tsx +0 -189
  94. package/src/components/layout/breadcrumbs.tsx +0 -77
  95. package/src/components/layout/document-title.tsx +0 -31
  96. package/src/components/layout/navigation-progress.tsx +0 -52
  97. package/src/components/layout/page-skeleton.tsx +0 -49
  98. package/src/providers/urql-client.ts +0 -86
  99. package/src/router/config.tsx +0 -534
  100. package/src/router/layouts/dashboard-layout.tsx +0 -20
  101. package/src/router/layouts/root-layout.tsx +0 -69
  102. package/src/router/loaders/auth-loader.ts +0 -32
  103. package/src/router/loaders/business-loader.ts +0 -25
  104. package/src/router/loaders/charge-loader.ts +0 -25
  105. package/src/router/loaders/index.ts +0 -17
  106. package/src/router/routes.ts +0 -88
  107. package/src/router/types.ts +0 -62
@@ -1,189 +0,0 @@
1
- import { type ReactElement } from 'react';
2
- import { AlertCircle, Home, RefreshCw } from 'lucide-react';
3
- import { isRouteErrorResponse, Link, useRouteError } from 'react-router-dom';
4
- import { ROUTES } from '../router/routes.js';
5
- import { Button } from './ui/button.js';
6
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/card.js';
7
-
8
- /**
9
- * Global error boundary for router errors
10
- * Handles different error types and provides appropriate UI
11
- */
12
- export function ErrorBoundary(): ReactElement {
13
- const error = useRouteError();
14
-
15
- // Handle route errors (404, 401, 500, etc.)
16
- if (isRouteErrorResponse(error)) {
17
- switch (error.status) {
18
- case 404:
19
- return (
20
- <ErrorLayout
21
- icon={<AlertCircle className="h-16 w-16 text-yellow-500" />}
22
- title="Page Not Found"
23
- description="The page you're looking for doesn't exist."
24
- statusCode={404}
25
- >
26
- <div className="flex gap-4">
27
- <Link to={ROUTES.HOME}>
28
- <Button variant="default">
29
- <Home className="mr-2 h-4 w-4" />
30
- Go Home
31
- </Button>
32
- </Link>
33
- <Button variant="outline" onClick={() => window.history.back()}>
34
- Go Back
35
- </Button>
36
- </div>
37
- </ErrorLayout>
38
- );
39
-
40
- case 401:
41
- return (
42
- <ErrorLayout
43
- icon={<AlertCircle className="h-16 w-16 text-red-500" />}
44
- title="Unauthorized"
45
- description="You need to be logged in to access this page."
46
- statusCode={401}
47
- >
48
- <Link to={ROUTES.LOGIN}>
49
- <Button variant="default">Go to Login</Button>
50
- </Link>
51
- </ErrorLayout>
52
- );
53
-
54
- case 403:
55
- return (
56
- <ErrorLayout
57
- icon={<AlertCircle className="h-16 w-16 text-red-500" />}
58
- title="Forbidden"
59
- description="You don't have permission to access this resource."
60
- statusCode={403}
61
- >
62
- <Link to={ROUTES.HOME}>
63
- <Button variant="default">
64
- <Home className="mr-2 h-4 w-4" />
65
- Go Home
66
- </Button>
67
- </Link>
68
- </ErrorLayout>
69
- );
70
-
71
- case 500:
72
- return (
73
- <ErrorLayout
74
- icon={<AlertCircle className="h-16 w-16 text-red-500" />}
75
- title="Server Error"
76
- description="Something went wrong on our end. We're working to fix it."
77
- statusCode={500}
78
- >
79
- <div className="flex gap-4">
80
- <Button variant="default" onClick={() => window.location.reload()}>
81
- <RefreshCw className="mr-2 h-4 w-4" />
82
- Reload Page
83
- </Button>
84
- <Link to={ROUTES.HOME}>
85
- <Button variant="outline">
86
- <Home className="mr-2 h-4 w-4" />
87
- Go Home
88
- </Button>
89
- </Link>
90
- </div>
91
- </ErrorLayout>
92
- );
93
-
94
- default:
95
- return (
96
- <ErrorLayout
97
- icon={<AlertCircle className="h-16 w-16 text-orange-500" />}
98
- title={`Error ${error.status}`}
99
- description={error.statusText || 'An unexpected error occurred'}
100
- statusCode={error.status}
101
- >
102
- <Link to={ROUTES.HOME}>
103
- <Button variant="default">
104
- <Home className="mr-2 h-4 w-4" />
105
- Go Home
106
- </Button>
107
- </Link>
108
- </ErrorLayout>
109
- );
110
- }
111
- }
112
-
113
- // Handle generic JavaScript errors
114
- const genericError = error as Error;
115
- const isDevelopment = import.meta.env.DEV;
116
-
117
- return (
118
- <ErrorLayout
119
- icon={<AlertCircle className="h-16 w-16 text-red-500" />}
120
- title="Unexpected Error"
121
- description="An unexpected error occurred. Please try again."
122
- >
123
- {isDevelopment && genericError.message && (
124
- <Card className="max-w-2xl mt-4 bg-red-50 border-red-200">
125
- <CardHeader>
126
- <CardTitle className="text-sm text-red-700">Error Details (Dev Only)</CardTitle>
127
- </CardHeader>
128
- <CardContent>
129
- <pre className="text-xs text-red-600 overflow-auto">
130
- {genericError.message}
131
- {genericError.stack && `\n\n${genericError.stack}`}
132
- </pre>
133
- </CardContent>
134
- </Card>
135
- )}
136
- <div className="flex gap-4 mt-4">
137
- <Button variant="default" onClick={() => window.location.reload()}>
138
- <RefreshCw className="mr-2 h-4 w-4" />
139
- Reload Page
140
- </Button>
141
- <Link to={ROUTES.HOME}>
142
- <Button variant="outline">
143
- <Home className="mr-2 h-4 w-4" />
144
- Go Home
145
- </Button>
146
- </Link>
147
- </div>
148
- </ErrorLayout>
149
- );
150
- }
151
-
152
- /**
153
- * Reusable error layout component
154
- */
155
- interface ErrorLayoutProps {
156
- icon: ReactElement;
157
- title: string;
158
- description: string;
159
- statusCode?: number;
160
- children?: React.ReactNode;
161
- }
162
-
163
- function ErrorLayout({
164
- icon,
165
- title,
166
- description,
167
- statusCode,
168
- children,
169
- }: ErrorLayoutProps): ReactElement {
170
- return (
171
- <div className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
172
- <Card className="max-w-md w-full">
173
- <CardHeader className="text-center space-y-4">
174
- <div className="flex justify-center">{icon}</div>
175
- <div>
176
- <CardTitle className="text-2xl font-bold">
177
- {title}
178
- {statusCode && (
179
- <span className="ml-2 text-sm text-muted-foreground">({statusCode})</span>
180
- )}
181
- </CardTitle>
182
- <CardDescription className="mt-2">{description}</CardDescription>
183
- </div>
184
- </CardHeader>
185
- <CardContent className="flex flex-col items-center space-y-4">{children}</CardContent>
186
- </Card>
187
- </div>
188
- );
189
- }
@@ -1,77 +0,0 @@
1
- import { Fragment, type ReactElement } from 'react';
2
- import { ChevronRight, Home } from 'lucide-react';
3
- import { Link, useMatches } from 'react-router-dom';
4
-
5
- interface RouteHandle {
6
- breadcrumb?: string | ((data?: unknown) => string);
7
- title?: string | ((data?: unknown) => string);
8
- [key: string]: unknown;
9
- }
10
-
11
- interface Crumb {
12
- title: string;
13
- path: string;
14
- isLast: boolean;
15
- }
16
-
17
- /**
18
- * Breadcrumbs component - displays navigation path
19
- * Reads breadcrumb data from route handles
20
- */
21
- export function Breadcrumbs(): ReactElement {
22
- const matches = useMatches();
23
-
24
- // Build breadcrumb trail from matched routes
25
- const crumbs: Crumb[] = matches
26
- .filter(match => {
27
- const handle = match.handle as RouteHandle | undefined;
28
- return handle?.breadcrumb;
29
- })
30
- .map((match, index, array) => {
31
- const handle = match.handle as RouteHandle;
32
- const title =
33
- typeof handle.breadcrumb === 'function'
34
- ? handle.breadcrumb(match.data)
35
- : handle.breadcrumb || 'Page';
36
-
37
- return {
38
- title,
39
- path: match.pathname,
40
- isLast: index === array.length - 1,
41
- };
42
- });
43
-
44
- // Don't render if no breadcrumbs
45
- if (crumbs.length === 0) {
46
- return <div className="h-8" />; // Spacer to maintain layout
47
- }
48
-
49
- return (
50
- <nav aria-label="Breadcrumb" className="flex items-center space-x-1 text-sm text-gray-600">
51
- {/* Home icon as first item */}
52
- <Link
53
- to="/"
54
- className="flex items-center hover:text-gray-900 transition-colors"
55
- aria-label="Home"
56
- >
57
- <Home className="h-4 w-4" />
58
- </Link>
59
-
60
- {/* Breadcrumb items */}
61
- {crumbs.map((crumb, index) => (
62
- <Fragment key={`${crumb.path}-${index}`}>
63
- <ChevronRight className="h-4 w-4 text-gray-400" />
64
- {crumb.isLast ? (
65
- <span className="font-medium text-gray-900" aria-current="page">
66
- {crumb.title}
67
- </span>
68
- ) : (
69
- <Link to={crumb.path} className="hover:text-gray-900 transition-colors">
70
- {crumb.title}
71
- </Link>
72
- )}
73
- </Fragment>
74
- ))}
75
- </nav>
76
- );
77
- }
@@ -1,31 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { useMatches } from 'react-router-dom';
3
-
4
- interface RouteHandle {
5
- title?: string | ((data?: unknown) => string);
6
- breadcrumb?: string | ((data?: unknown) => string);
7
- [key: string]: unknown;
8
- }
9
-
10
- /**
11
- * Component that updates document title based on route handle
12
- * Place this in the root layout to automatically update titles
13
- */
14
- export function DocumentTitle() {
15
- const matches = useMatches();
16
-
17
- useEffect(() => {
18
- const lastMatch = matches[matches.length - 1];
19
- const handle = lastMatch?.handle as RouteHandle | undefined;
20
-
21
- if (handle?.title) {
22
- const title =
23
- typeof handle.title === 'function' ? handle.title(lastMatch.data) : handle.title;
24
- document.title = `${title} - Accounter`;
25
- } else {
26
- document.title = 'Accounter';
27
- }
28
- }, [matches]);
29
-
30
- return <div style={{ display: 'none' }} />;
31
- }
@@ -1,52 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { useNavigation } from 'react-router-dom';
3
- import { Progress } from '../ui/progress.js';
4
-
5
- /**
6
- * Global navigation progress indicator
7
- * Shows a loading bar at the top of the page during route transitions
8
- */
9
- export function NavigationProgress() {
10
- const navigation = useNavigation();
11
- const [progress, setProgress] = useState(0);
12
- const isLoading = navigation.state === 'loading';
13
-
14
- useEffect(() => {
15
- if (isLoading) {
16
- // Start at 20% when loading begins
17
- setProgress(20);
18
-
19
- // Simulate progress
20
- const interval = setInterval(() => {
21
- setProgress(prev => {
22
- // Asymptotically approach 90% but never quite reach it
23
- const next = prev + (90 - prev) * 0.1;
24
- return Math.min(next, 90);
25
- });
26
- }, 300);
27
-
28
- return () => clearInterval(interval);
29
- }
30
-
31
- // Complete the progress when loading finishes
32
- setProgress(100);
33
-
34
- // Reset after animation
35
- const timeout = setTimeout(() => {
36
- setProgress(0);
37
- }, 500);
38
-
39
- return () => clearTimeout(timeout);
40
- }, [isLoading]);
41
-
42
- // Don't render anything if not loading and progress is 0
43
- if (!isLoading && progress === 0) {
44
- return null;
45
- }
46
-
47
- return (
48
- <div className="fixed top-0 left-0 right-0 z-50 h-1">
49
- <Progress value={progress} className="h-1 rounded-none transition-all duration-300" />
50
- </div>
51
- );
52
- }
@@ -1,49 +0,0 @@
1
- import type { ReactElement } from 'react';
2
- import { Skeleton } from '../ui/skeleton.js';
3
-
4
- /**
5
- * Generic page loading skeleton
6
- * Displayed during route transitions
7
- */
8
- export function PageSkeleton(): ReactElement {
9
- return (
10
- <div className="flex flex-col gap-4 p-4">
11
- <Skeleton className="h-12 w-64" /> {/* Page title */}
12
- <div className="flex gap-4">
13
- <Skeleton className="h-10 w-32" /> {/* Button/filter */}
14
- <Skeleton className="h-10 w-32" />
15
- </div>
16
- <Skeleton className="h-96 w-full" /> {/* Main content area */}
17
- </div>
18
- );
19
- }
20
-
21
- /**
22
- * Table loading skeleton
23
- */
24
- export function TableSkeleton(): ReactElement {
25
- return (
26
- <div className="flex flex-col gap-2">
27
- <Skeleton className="h-12 w-full" /> {/* Header */}
28
- {Array.from({ length: 8 }).map((_, i) => (
29
- <Skeleton key={i} className="h-16 w-full" />
30
- ))}
31
- </div>
32
- );
33
- }
34
-
35
- /**
36
- * Report loading skeleton
37
- */
38
- export function ReportSkeleton(): ReactElement {
39
- return (
40
- <div className="flex flex-col gap-6">
41
- <Skeleton className="h-16 w-96" /> {/* Report title */}
42
- <div className="flex gap-4">
43
- <Skeleton className="h-10 w-48" /> {/* Date filter */}
44
- <Skeleton className="h-10 w-32" /> {/* Export button */}
45
- </div>
46
- <Skeleton className="h-[600px] w-full" /> {/* Report content */}
47
- </div>
48
- );
49
- }
@@ -1,86 +0,0 @@
1
- import {
2
- createClient,
3
- fetchExchange,
4
- mapExchange,
5
- type AnyVariables,
6
- type Client,
7
- type Operation,
8
- } from 'urql';
9
- import { authExchange } from '@urql/exchange-auth';
10
- import { UserService } from '../services/user-service.js';
11
-
12
- /**
13
- * Singleton URQL client for use in loaders and server-side operations
14
- * This is separate from the Provider client to avoid React context dependencies
15
- */
16
- let globalClient: Client | null = null;
17
-
18
- export function getUrqlClient(): Client {
19
- if (globalClient) {
20
- return globalClient;
21
- }
22
-
23
- const authService = new UserService();
24
-
25
- let url: string;
26
- switch (import.meta.env.MODE) {
27
- case 'production': {
28
- url = 'https://accounter.onrender.com/graphql';
29
- break;
30
- }
31
- case 'staging': {
32
- url = 'https://accounter-staging.onrender.com/graphql';
33
- break;
34
- }
35
- default: {
36
- url = 'http://localhost:4000/graphql';
37
- break;
38
- }
39
- }
40
-
41
- globalClient = createClient({
42
- url,
43
- exchanges: [
44
- mapExchange({
45
- onResult(result) {
46
- if (result.error?.networkError) {
47
- console.error('Network Error:', result.error.networkError);
48
- }
49
- },
50
- }),
51
- authExchange(async utils => {
52
- return {
53
- addAuthToOperation(operation): Operation<void, AnyVariables> {
54
- const token = authService.authToken();
55
- if (!token) {
56
- return operation;
57
- }
58
- return utils.appendHeaders(operation, {
59
- Authorization: token,
60
- });
61
- },
62
- didAuthError(error, _operation): boolean {
63
- return (
64
- error?.response?.status === 401 ||
65
- error?.graphQLErrors?.some(e => e.extensions?.code === 'FORBIDDEN')
66
- );
67
- },
68
- async refreshAuth(): Promise<void> {
69
- authService.logout();
70
- // Redirect handled by route loader
71
- },
72
- };
73
- }),
74
- fetchExchange,
75
- ],
76
- });
77
-
78
- return globalClient;
79
- }
80
-
81
- /**
82
- * Reset the global client (useful for tests or logout)
83
- */
84
- export function resetUrqlClient(): void {
85
- globalClient = null;
86
- }