@spaceinvoices/react-ui 0.4.6 → 0.4.7

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 (55) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +60 -44
  4. package/src/components/credit-notes/create/create-credit-note-form.tsx +52 -42
  5. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -92
  6. package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +48 -82
  7. package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +22 -31
  8. package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +33 -48
  9. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +56 -76
  10. package/src/components/dashboard/shared/index.ts +1 -1
  11. package/src/components/dashboard/shared/use-revenue-data.ts +106 -182
  12. package/src/components/dashboard/shared/use-stats-counts.ts +18 -68
  13. package/src/components/dashboard/shared/use-stats-query.ts +35 -5
  14. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +57 -75
  15. package/src/components/dashboard/top-customers-chart/use-top-customers.ts +38 -49
  16. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +3 -2
  17. package/src/components/documents/create/document-details-section.tsx +6 -4
  18. package/src/components/documents/create/document-recipient-section.tsx +30 -1
  19. package/src/components/documents/create/live-preview.tsx +15 -28
  20. package/src/components/documents/create/prepare-document-submission.ts +1 -0
  21. package/src/components/documents/create/use-document-customer-form.ts +4 -0
  22. package/src/components/documents/shared/document-preview-skeleton.tsx +63 -0
  23. package/src/components/documents/shared/index.ts +1 -0
  24. package/src/components/documents/view/document-actions-bar.tsx +29 -7
  25. package/src/components/entities/settings/tax-rules-settings-form.tsx +31 -13
  26. package/src/components/estimates/create/create-estimate-form.tsx +3 -2
  27. package/src/components/invoices/create/create-invoice-form.tsx +134 -62
  28. package/src/components/invoices/create/locales/de.ts +6 -0
  29. package/src/components/invoices/create/locales/es.ts +6 -0
  30. package/src/components/invoices/create/locales/fr.ts +6 -0
  31. package/src/components/invoices/create/locales/hr.ts +6 -0
  32. package/src/components/invoices/create/locales/it.ts +6 -0
  33. package/src/components/invoices/create/locales/nl.ts +6 -0
  34. package/src/components/invoices/create/locales/pl.ts +6 -0
  35. package/src/components/invoices/create/locales/pt.ts +6 -0
  36. package/src/components/invoices/create/locales/sl.ts +6 -0
  37. package/src/components/invoices/invoices.hooks.ts +1 -1
  38. package/src/components/ui/progress.tsx +27 -0
  39. package/src/generate-schemas.ts +15 -2
  40. package/src/generated/schemas/advanceinvoice.ts +2 -0
  41. package/src/generated/schemas/creditnote.ts +2 -0
  42. package/src/generated/schemas/customer.ts +2 -0
  43. package/src/generated/schemas/deliverynote.ts +2 -0
  44. package/src/generated/schemas/entity.ts +10 -0
  45. package/src/generated/schemas/estimate.ts +2 -0
  46. package/src/generated/schemas/finasettings.ts +4 -3
  47. package/src/generated/schemas/invoice.ts +2 -0
  48. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +16 -10
  49. package/src/generated/schemas/rendercreditnotepreview_body.ts +16 -10
  50. package/src/generated/schemas/renderdeliverynotepreview_body.ts +14 -7
  51. package/src/generated/schemas/renderestimatepreview_body.ts +14 -7
  52. package/src/generated/schemas/renderinvoicepreview_body.ts +16 -10
  53. package/src/generated/schemas/startpdfexport_body.ts +12 -17
  54. package/src/hooks/use-transaction-type-check.ts +152 -0
  55. package/src/hooks/use-vies-check.ts +7 -131
@@ -1,47 +1,38 @@
1
1
  /**
2
2
  * Payment methods hook using the entity stats API.
3
3
  * Server-side aggregation by payment type.
4
+ * Sends 1 query in a batch request.
4
5
  */
5
6
  import type { StatsQueryDataItem } from "@spaceinvoices/js-sdk";
6
- import { useQuery } from "@tanstack/react-query";
7
- import { useSDK } from "@/ui/providers/sdk-provider";
8
- import { STATS_QUERY_CACHE_KEY } from "../shared/use-stats-query";
7
+ import { useStatsQuery } from "../shared/use-stats-query";
9
8
 
10
9
  export const PAYMENT_METHODS_CACHE_KEY = "dashboard-payment-methods";
11
10
 
12
11
  export type PaymentMethodsData = { type: string; count: number; amount: number }[];
13
12
 
14
13
  export function usePaymentMethodsData(entityId: string | undefined) {
15
- const { sdk } = useSDK();
16
-
17
- const query = useQuery({
18
- queryKey: [STATS_QUERY_CACHE_KEY, entityId, "payment-methods"],
19
- queryFn: async () => {
20
- if (!entityId || !sdk) throw new Error("Missing entity or SDK");
21
- return sdk.entityStats.queryEntityStats(
22
- {
23
- metrics: [
24
- { type: "count", alias: "count" },
25
- { type: "sum", field: "amount", alias: "amount" },
26
- ],
27
- table: "payments",
28
- group_by: ["type"],
29
- order_by: [{ field: "amount", direction: "desc" }],
30
- },
31
- { entity_id: entityId },
32
- );
14
+ const query = useStatsQuery(
15
+ entityId,
16
+ {
17
+ metrics: [
18
+ { type: "count", alias: "count" },
19
+ { type: "sum", field: "amount", alias: "amount" },
20
+ ],
21
+ table: "payments",
22
+ group_by: ["type"],
23
+ order_by: [{ field: "amount", direction: "desc" }],
33
24
  },
34
- enabled: !!entityId && !!sdk,
35
- staleTime: 120_000,
36
- select: (response) => {
37
- const data = response.data || [];
38
- return (data as StatsQueryDataItem[]).map((row) => ({
39
- type: String(row.type || "other"),
40
- count: Number(row.count) || 0,
41
- amount: Number(row.amount) || 0,
42
- }));
25
+ {
26
+ select: (response) => {
27
+ const data = response.data || [];
28
+ return (data as StatsQueryDataItem[]).map((row) => ({
29
+ type: String(row.type || "other"),
30
+ count: Number(row.count) || 0,
31
+ amount: Number(row.amount) || 0,
32
+ }));
33
+ },
43
34
  },
44
- });
35
+ );
45
36
 
46
37
  return {
47
38
  data: query.data || [],
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * Payment trend hook using the entity stats API.
3
3
  * Server-side aggregation by month for accurate trend data.
4
+ * Sends 1 query in a batch request.
4
5
  */
5
6
  import type { StatsQueryDataItem } from "@spaceinvoices/js-sdk";
6
- import { useQuery } from "@tanstack/react-query";
7
- import { useSDK } from "@/ui/providers/sdk-provider";
8
- import { STATS_QUERY_CACHE_KEY } from "../shared/use-stats-query";
7
+ import { useStatsQuery } from "../shared/use-stats-query";
9
8
 
10
9
  export const PAYMENT_TREND_CACHE_KEY = "dashboard-payment-trend";
11
10
 
@@ -13,9 +12,7 @@ function getLastMonths(count: number): { months: string[]; startDate: string; en
13
12
  const months: string[] = [];
14
13
  const now = new Date();
15
14
 
16
- // Start of the month 'count-1' months ago
17
15
  const startDate = new Date(now.getFullYear(), now.getMonth() - (count - 1), 1);
18
- // End of current month
19
16
  const endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
20
17
 
21
18
  for (let i = count - 1; i >= 0; i--) {
@@ -33,56 +30,44 @@ function getLastMonths(count: number): { months: string[]; startDate: string; en
33
30
  export type PaymentTrendData = { month: string; amount: number }[];
34
31
 
35
32
  export function usePaymentTrendData(entityId: string | undefined) {
36
- const { sdk } = useSDK();
37
-
38
33
  const { months, startDate, endDate } = getLastMonths(6);
39
34
 
40
- const query = useQuery({
41
- queryKey: [STATS_QUERY_CACHE_KEY, entityId, "payment-trend", startDate, endDate],
42
- queryFn: async () => {
43
- if (!entityId || !sdk) throw new Error("Missing entity or SDK");
44
- return sdk.entityStats.queryEntityStats(
45
- {
46
- metrics: [{ type: "sum", field: "amount_converted", alias: "amount" }],
47
- table: "payments",
48
- date_from: startDate,
49
- date_to: endDate,
50
- group_by: ["month", "currency_code"], // Include currency for display
51
- order_by: [{ field: "month", direction: "asc" }],
52
- },
53
- { entity_id: entityId },
54
- );
35
+ const query = useStatsQuery(
36
+ entityId,
37
+ {
38
+ metrics: [{ type: "sum", field: "amount_converted", alias: "amount" }],
39
+ table: "payments",
40
+ date_from: startDate,
41
+ date_to: endDate,
42
+ group_by: ["month", "currency_code"],
43
+ order_by: [{ field: "month", direction: "asc" }],
55
44
  },
56
- enabled: !!entityId && !!sdk,
57
- staleTime: 120_000,
58
- select: (response) => {
59
- // Build a map of all months with 0 amount
60
- const monthMap: Record<string, number> = {};
61
- for (const month of months) {
62
- monthMap[month] = 0;
63
- }
64
-
65
- // Fill in the actual amounts from the API response
66
- // Sum up amounts per month (in case of multiple rows due to currency_code grouping)
67
- const data = response.data || [];
68
- let currency = "EUR";
69
- for (const row of data as StatsQueryDataItem[]) {
70
- const month = String(row.month);
71
- if (month in monthMap) {
72
- monthMap[month] += Number(row.amount) || 0;
45
+ {
46
+ select: (response) => {
47
+ const monthMap: Record<string, number> = {};
48
+ for (const month of months) {
49
+ monthMap[month] = 0;
73
50
  }
74
- // Get currency from first row with data
75
- if (row.currency_code && currency === "EUR") {
76
- currency = String(row.currency_code);
51
+
52
+ const data = response.data || [];
53
+ let currency = "EUR";
54
+ for (const row of data as StatsQueryDataItem[]) {
55
+ const month = String(row.month);
56
+ if (month in monthMap) {
57
+ monthMap[month] += Number(row.amount) || 0;
58
+ }
59
+ if (row.currency_code && currency === "EUR") {
60
+ currency = String(row.currency_code);
61
+ }
77
62
  }
78
- }
79
63
 
80
- return {
81
- data: months.map((month) => ({ month, amount: monthMap[month] })),
82
- currency, // Currency from payment data
83
- };
64
+ return {
65
+ data: months.map((month) => ({ month, amount: monthMap[month] })),
66
+ currency,
67
+ };
68
+ },
84
69
  },
85
- });
70
+ );
86
71
 
87
72
  return {
88
73
  data: query.data?.data || [],
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * Revenue trend hook using the entity stats API.
3
3
  * Server-side aggregation by month for accurate trend data.
4
+ * Sends 2 queries in a single batch request.
4
5
  */
5
- import type { StatsQueryDataItem } from "@spaceinvoices/js-sdk";
6
- import { useQueries } from "@tanstack/react-query";
7
- import { useSDK } from "@/ui/providers/sdk-provider";
8
- import { STATS_QUERY_CACHE_KEY } from "../shared/use-stats-query";
6
+ import type { StatsQueryDataItem, StatsQueryRequest } from "@spaceinvoices/js-sdk";
7
+ import { useStatsBatchQuery } from "../shared/use-stats-query";
9
8
 
10
9
  export const REVENUE_TREND_CACHE_KEY = "dashboard-revenue-trend";
11
10
 
@@ -13,9 +12,7 @@ function getLastMonths(count: number): { months: string[]; startDate: string; en
13
12
  const months: string[] = [];
14
13
  const now = new Date();
15
14
 
16
- // Start of the month 'count-1' months ago
17
15
  const startDate = new Date(now.getFullYear(), now.getMonth() - (count - 1), 1);
18
- // End of current month
19
16
  const endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
20
17
 
21
18
  for (let i = count - 1; i >= 0; i--) {
@@ -33,11 +30,9 @@ function getLastMonths(count: number): { months: string[]; startDate: string; en
33
30
  export type RevenueTrendData = { month: string; revenue: number }[];
34
31
 
35
32
  export function useRevenueTrendData(entityId: string | undefined) {
36
- const { sdk } = useSDK();
37
-
38
33
  const { months, startDate, endDate } = getLastMonths(6);
39
34
 
40
- const sharedQueryParams = {
35
+ const sharedParams = {
41
36
  date_from: startDate,
42
37
  date_to: endDate,
43
38
  filters: { is_draft: false },
@@ -45,78 +40,63 @@ export function useRevenueTrendData(entityId: string | undefined) {
45
40
  order_by: [{ field: "month", direction: "asc" as const }],
46
41
  };
47
42
 
48
- const queries = useQueries({
49
- queries: [
50
- {
51
- queryKey: [STATS_QUERY_CACHE_KEY, entityId, "revenue-trend", startDate, endDate],
52
- queryFn: async () => {
53
- if (!entityId || !sdk) throw new Error("Missing entity or SDK");
54
- return sdk.entityStats.queryEntityStats(
55
- {
56
- metrics: [{ type: "sum", field: "total_with_tax_converted", alias: "revenue" }],
57
- table: "invoices",
58
- ...sharedQueryParams,
59
- },
60
- { entity_id: entityId },
61
- );
62
- },
63
- enabled: !!entityId && !!sdk,
64
- staleTime: 120_000,
65
- },
66
- {
67
- queryKey: [STATS_QUERY_CACHE_KEY, entityId, "cn-revenue-trend", startDate, endDate],
68
- queryFn: async () => {
69
- if (!entityId || !sdk) throw new Error("Missing entity or SDK");
70
- return sdk.entityStats.queryEntityStats(
71
- {
72
- metrics: [{ type: "sum", field: "total_with_tax_converted", alias: "revenue" }],
73
- table: "credit_notes",
74
- ...sharedQueryParams,
75
- },
76
- { entity_id: entityId },
77
- );
78
- },
79
- enabled: !!entityId && !!sdk,
80
- staleTime: 120_000,
81
- },
82
- ],
83
- });
43
+ const queries: StatsQueryRequest[] = [
44
+ // [0] Invoice revenue by month
45
+ {
46
+ metrics: [{ type: "sum", field: "total_with_tax_converted", alias: "revenue" }],
47
+ table: "invoices",
48
+ ...sharedParams,
49
+ },
50
+ // [1] Credit note revenue by month
51
+ {
52
+ metrics: [{ type: "sum", field: "total_with_tax_converted", alias: "revenue" }],
53
+ table: "credit_notes",
54
+ ...sharedParams,
55
+ },
56
+ ];
84
57
 
85
- const [invoiceQuery, cnQuery] = queries;
58
+ const { data: results, isLoading } = useStatsBatchQuery(entityId, "revenue-trend", queries, {
59
+ select: (batch) => {
60
+ // Build month maps
61
+ const monthMap: Record<string, number> = {};
62
+ const cnMonthMap: Record<string, number> = {};
63
+ for (const month of months) {
64
+ monthMap[month] = 0;
65
+ cnMonthMap[month] = 0;
66
+ }
86
67
 
87
- // Build month maps
88
- const monthMap: Record<string, number> = {};
89
- const cnMonthMap: Record<string, number> = {};
90
- for (const month of months) {
91
- monthMap[month] = 0;
92
- cnMonthMap[month] = 0;
93
- }
68
+ // Fill invoice revenue per month
69
+ const invoiceData = (batch[0].data || []) as StatsQueryDataItem[];
70
+ let currency = "EUR";
71
+ for (const row of invoiceData) {
72
+ const month = String(row.month);
73
+ if (month in monthMap) {
74
+ monthMap[month] += Number(row.revenue) || 0;
75
+ }
76
+ if (row.quote_currency && currency === "EUR") {
77
+ currency = String(row.quote_currency);
78
+ }
79
+ }
94
80
 
95
- // Fill invoice revenue per month
96
- const invoiceData = (invoiceQuery.data?.data || []) as StatsQueryDataItem[];
97
- let currency = "EUR";
98
- for (const row of invoiceData) {
99
- const month = String(row.month);
100
- if (month in monthMap) {
101
- monthMap[month] += Number(row.revenue) || 0;
102
- }
103
- if (row.quote_currency && currency === "EUR") {
104
- currency = String(row.quote_currency);
105
- }
106
- }
81
+ // Fill credit note revenue per month
82
+ const cnData = (batch[1].data || []) as StatsQueryDataItem[];
83
+ for (const row of cnData) {
84
+ const month = String(row.month);
85
+ if (month in cnMonthMap) {
86
+ cnMonthMap[month] += Number(row.revenue) || 0;
87
+ }
88
+ }
107
89
 
108
- // Fill credit note revenue per month
109
- const cnData = (cnQuery.data?.data || []) as StatsQueryDataItem[];
110
- for (const row of cnData) {
111
- const month = String(row.month);
112
- if (month in cnMonthMap) {
113
- cnMonthMap[month] += Number(row.revenue) || 0;
114
- }
115
- }
90
+ return {
91
+ data: months.map((month) => ({ month, revenue: monthMap[month] - cnMonthMap[month] })),
92
+ currency,
93
+ };
94
+ },
95
+ });
116
96
 
117
97
  return {
118
- data: months.map((month) => ({ month, revenue: monthMap[month] - cnMonthMap[month] })),
119
- currency,
120
- isLoading: queries.some((q) => q.isLoading),
98
+ data: results?.data || [],
99
+ currency: results?.currency || "EUR",
100
+ isLoading,
121
101
  };
122
102
  }
@@ -2,4 +2,4 @@ export type { RevenueData } from "./use-revenue-data";
2
2
  export { REVENUE_DATA_CACHE_KEY, useRevenueData } from "./use-revenue-data";
3
3
  export type { StatsCountsData } from "./use-stats-counts";
4
4
  export { STATS_COUNTS_CACHE_KEY, useStatsCountsData } from "./use-stats-counts";
5
- export { STATS_QUERY_CACHE_KEY, useStatsQuery } from "./use-stats-query";
5
+ export { STATS_QUERY_CACHE_KEY, useStatsBatchQuery, useStatsQuery } from "./use-stats-query";