@accounter/client 0.0.8-alpha-20251030162303-87017b2c2addf0e61478260aac336b9343f15c98 → 0.0.8-alpha-20251031025517-bd142395bc1d7267ab00d6b53b116062b581b7d8

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 (104) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/dist/assets/{Checkbox-CLE7WylX.js → Checkbox-CMTNcrRo.js} +1 -1
  3. package/dist/assets/{MultiSelect-SsgUtHuW.js → MultiSelect-DP26KzMa.js} +1 -1
  4. package/dist/assets/{Progress-D7j8SJRp.js → Progress-C3jVWDXK.js} +1 -1
  5. package/dist/assets/{Table-DpZKU9e6.js → Table-c1ug6Rpw.js} +1 -1
  6. package/dist/assets/{Typography-DOCvIzjw.js → Typography-BC-9NaKB.js} +1 -1
  7. package/dist/assets/{YearPickerInput-BbyQMsmW.js → YearPickerInput-CNSe9Fno.js} +1 -1
  8. package/dist/assets/{accordion-KRd9M_7N.js → accordion-CLvZdMsA.js} +1 -1
  9. package/dist/assets/{accountant-approvals-BWkXiUJx.js → accountant-approvals-BbNBYszL.js} +1 -1
  10. package/dist/assets/{accounter-table-BvOYdMv2.js → accounter-table-C7UgjlTA.js} +1 -1
  11. package/dist/assets/{addDays-HTdY9JyJ.js → addDays-CB-j-d4t.js} +1 -1
  12. package/dist/assets/{all-charges-uOrXkSoe.js → all-charges-vuUUzmwW.js} +1 -1
  13. package/dist/assets/{arrow-up-down-D0e6luFS.js → arrow-up-down-DWlT-GED.js} +1 -1
  14. package/dist/assets/{building-2-BScQAy2y.js → building-2-Dkd3B-3N.js} +1 -1
  15. package/dist/assets/business-BuVKb8Oy.js +37 -0
  16. package/dist/assets/{business-extended-info-BPdDug4k.js → business-extended-info-B4Wt-Sq3.js} +1 -1
  17. package/dist/assets/{business-header-ScM944FH.js → business-header-BpYfBk40.js} +1 -1
  18. package/dist/assets/{business-ledger-filters-C6zdPVNQ.js → business-ledger-filters-ByAYFfgh.js} +1 -1
  19. package/dist/assets/{business-ledger-single-D_gxQY7c.js → business-ledger-single-cLd56KYs.js} +1 -1
  20. package/dist/assets/{business-trip-BD6qMULS.js → business-trip-BWUbbHEK.js} +1 -1
  21. package/dist/assets/{charge-CXgCTI2e.js → charge-DyLqPZn0.js} +1 -1
  22. package/dist/assets/{charges-filters-DhYogrgu.js → charges-filters-CUyYbpwk.js} +1 -1
  23. package/dist/assets/{charges-ledger-validation-K96Gpr99.js → charges-ledger-validation-Br2BBUCN.js} +1 -1
  24. package/dist/assets/{charges-table-Cff0tibm.js → charges-table-Cw-X1ZkK.js} +6 -6
  25. package/dist/assets/{chart-Rag7RVt5.js → chart-TrN24kVd.js} +1 -1
  26. package/dist/assets/contracts-CbwbCzFG.js +16 -0
  27. package/dist/assets/{data-table-pagination-BenxjRXY.js → data-table-pagination-BZmytrQe.js} +2 -2
  28. package/dist/assets/{download-csv-button-8ow10rSS.js → download-csv-button-r9hq7Mun.js} +1 -1
  29. package/dist/assets/{edit-issue-document-modal-2d_PTbvO.js → edit-issue-document-modal-aZgmep8e.js} +1 -1
  30. package/dist/assets/{editable-business-trip-BFJ_Mqji.js → editable-business-trip-BCj8haJN.js} +2 -2
  31. package/dist/assets/{eye-off-BNMLF-BO.js → eye-off-Cd4HW5Ki.js} +1 -1
  32. package/dist/assets/{funnel-DW3_rS_8.js → funnel-DlU6IKDd.js} +1 -1
  33. package/dist/assets/{index-4ufIi3AX.js → index-4Zj8Hp3W.js} +2 -2
  34. package/dist/assets/{index-2unHvdGT.js → index-BGcp3XaM.js} +1 -1
  35. package/dist/assets/{index-B0Je179L.js → index-BM_DgFX-.js} +1 -1
  36. package/dist/assets/{index-Bo2SK7RM.js → index-BnDJ3EgW.js} +1 -1
  37. package/dist/assets/{index-DyLWk3js.js → index-Bo91VSNv.js} +1 -1
  38. package/dist/assets/{index-BHA96r33.js → index-BovGiTUZ.js} +1 -1
  39. package/dist/assets/{index-1iKxq5ag.js → index-Bt94reMP.js} +2 -2
  40. package/dist/assets/index-BwqfmUGW.js +1 -0
  41. package/dist/assets/index-C4ozKIHg.js +1 -0
  42. package/dist/assets/{index-BPS5RB7_.js → index-CLyrvG5S.js} +1 -1
  43. package/dist/assets/{index-CKNxDyu9.js → index-CS2mkstk.js} +1 -1
  44. package/dist/assets/index-CsxUWF65.js +1 -0
  45. package/dist/assets/index-Cuu0j4Ul.js +1 -0
  46. package/dist/assets/{index-BDUyPP2c.js → index-DOzNNsNU.js} +1 -1
  47. package/dist/assets/{index-Bp6IHcih.js → index-DPLJ9sZn.js} +1 -1
  48. package/dist/assets/index-Dl3yi4zQ.js +1 -0
  49. package/dist/assets/{index-VD71ra9C.js → index-DmC4088R.js} +2 -2
  50. package/dist/assets/{index-B2VI47XT.js → index-DnkSW9Wf.js} +1 -1
  51. package/dist/assets/{index-lMXNkFuw.js → index-Dzi5mI80.js} +2 -2
  52. package/dist/assets/{index-Bd-SKdyy.js → index-UOt3vExk.js} +196 -196
  53. package/dist/assets/{index-BQyZXdTq.js → index-VYPC3lji.js} +2 -2
  54. package/dist/assets/index-Wu-q9oyp.js +1 -0
  55. package/dist/assets/{index-DvvRs9Ha.js → index-as7vp0Ty.js} +1 -1
  56. package/dist/assets/{index-BCiHeRl-.js → index-jFDc_D4d.js} +1 -1
  57. package/dist/assets/{index-CEiIgRJ2.js → index-jpqj1MvA.js} +7 -7
  58. package/dist/assets/{index.es-C9I2aTP4.js → index.es-CuvVRlqN.js} +1 -1
  59. package/dist/assets/{insert-business-trip-modal-DVcWpJHr.js → insert-business-trip-modal-DyHAvuG6.js} +2 -2
  60. package/dist/assets/issue-document-BvIvdS89.js +1 -0
  61. package/dist/assets/{list-plus-B7wBrICK.js → list-plus-CYtq--On.js} +1 -1
  62. package/dist/assets/login-page-DcZw6k7i.js +1 -0
  63. package/dist/assets/{match-document-modal-CqP2SE2c.js → match-document-modal-Bs-5Zbj9.js} +4 -4
  64. package/dist/assets/{missing-info-charges-CIs_kE3P.js → missing-info-charges-e6O9it1V.js} +1 -1
  65. package/dist/assets/{modal-CwuHXtxz.js → modal-CqL_DX_G.js} +1 -1
  66. package/dist/assets/modify-contract-dialog-C8WuljxW.js +1 -0
  67. package/dist/assets/{page-layout-XgNPsCmr.js → page-layout-DfZJtWW1.js} +1 -1
  68. package/dist/assets/{page-not-found-CrFJMQNO.js → page-not-found-DnA0E-xR.js} +1 -1
  69. package/dist/assets/{panel-top-open-DU7alj-S.js → panel-top-open-D0lkFvhk.js} +1 -1
  70. package/dist/assets/{pencil-9DTTP5vx.js → pencil-DhN5v-Lb.js} +1 -1
  71. package/dist/assets/{report-commentary-row-BdS3qqMS.js → report-commentary-row-DvvXelmb.js} +1 -1
  72. package/dist/assets/{save-i8sPy_OW.js → save-CCZ-i4rw.js} +1 -1
  73. package/dist/assets/{similar-transactions-modal-CZAOYt-d.js → similar-transactions-modal-kFlTMg9C.js} +1 -1
  74. package/dist/assets/{sub-BL9nfaPD.js → sub-BKVGhLrr.js} +1 -1
  75. package/dist/assets/subMonths-Cbkj4M6-.js +1 -0
  76. package/dist/assets/{summary-Dfiju7xJ.js → summary-BuSv6nwb.js} +1 -1
  77. package/dist/assets/{toggle-expansion-button-BbVh8z6s.js → toggle-expansion-button-CojtDNtC.js} +1 -1
  78. package/dist/assets/tooltip-CoQF2skM.js +1 -0
  79. package/dist/assets/{use-url-query-5TFyEk1x.js → use-url-query-90MrwS1C.js} +1 -1
  80. package/dist/index.html +1 -1
  81. package/package.json +2 -2
  82. package/src/components/business/admin-business-section.tsx +282 -103
  83. package/src/components/clients/contracts/modify-contract-dialog.tsx +1 -7
  84. package/src/components/contracts/cells/date.tsx +5 -1
  85. package/src/components/contracts/columns.tsx +1 -1
  86. package/src/components/contracts/contracts-filter.tsx +8 -9
  87. package/src/components/contracts/index.tsx +0 -1
  88. package/src/components/contracts/issue-documents-modal.tsx +5 -3
  89. package/src/components/screens/businesses/clients/contracts/contracts.tsx +2 -4
  90. package/src/gql/gql.ts +3 -3
  91. package/src/gql/graphql.ts +52 -17
  92. package/dist/assets/business-qHY5sNtm.js +0 -37
  93. package/dist/assets/contracts-C26gq1yS.js +0 -16
  94. package/dist/assets/index-B86FoQmY.js +0 -1
  95. package/dist/assets/index-BZLSFBEt.js +0 -1
  96. package/dist/assets/index-CqIav7Xr.js +0 -1
  97. package/dist/assets/index-Dp9F68vS.js +0 -1
  98. package/dist/assets/index-NdA_oCxx.js +0 -1
  99. package/dist/assets/index-q3ev6JER.js +0 -1
  100. package/dist/assets/issue-document-BxTTlJ1T.js +0 -1
  101. package/dist/assets/login-page-BpgscuKm.js +0 -1
  102. package/dist/assets/modify-contract-dialog-BoeamC68.js +0 -1
  103. package/dist/assets/subMonths-DHPWOZP6.js +0 -1
  104. package/dist/assets/tooltip-C-fd9L1l.js +0 -1
@@ -2,8 +2,9 @@
2
2
 
3
3
  import type React from 'react';
4
4
  import { useEffect, useState } from 'react';
5
- import { Save, Shield } from 'lucide-react';
6
- import { useForm } from 'react-hook-form';
5
+ import { format } from 'date-fns';
6
+ import { Plus, Save, Shield, X } from 'lucide-react';
7
+ import { useFieldArray, useForm } from 'react-hook-form';
7
8
  import { z } from 'zod';
8
9
  import { Button } from '@/components/ui/button.js';
9
10
  import {
@@ -38,6 +39,7 @@ import {
38
39
  } from '@/helpers/index.js';
39
40
  import { useUpdateAdminBusiness } from '@/hooks/use-update-admin-business.js';
40
41
  import { zodResolver } from '@hookform/resolvers/zod';
42
+ import { Label } from '../ui/label';
41
43
  import { Separator } from '../ui/separator';
42
44
 
43
45
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- used by codegen
@@ -47,59 +49,81 @@ import { Separator } from '../ui/separator';
47
49
  ... on LtdFinancialEntity {
48
50
  adminInfo {
49
51
  id
50
- withholdingTaxBookNumber
51
- withholdingTaxFileNumber
52
- socialSecurityEmployerId
53
- taxAdvancesRate
54
- taxAdvancesId
55
52
  registrationDate
53
+ withholdingTaxAnnualIds {
54
+ id
55
+ year
56
+ }
57
+ withholdingTaxCompanyId
58
+ socialSecurityEmployerIds {
59
+ id
60
+ year
61
+ }
62
+ socialSecurityDeductionsId
63
+ taxAdvancesAnnualIds {
64
+ id
65
+ year
66
+ }
67
+ taxAdvancesRates {
68
+ date
69
+ rate
70
+ }
56
71
  }
57
72
  }
58
73
  }
59
74
  `;
60
75
 
76
+ const annualIdSchema = z.object({
77
+ year: z.number().min(2000).max(2100),
78
+ id: z.string().min(1, { message: 'ID is required' }),
79
+ });
80
+
61
81
  const adminBusinessFormSchema = z.object({
62
- withholdingTaxBookNumber: z.string().min(1, {
63
- message: 'Withholding Tax Book Number is required',
64
- }),
65
- withholdingTaxFileNumber: z.string().min(1, {
66
- message: 'Withholding Tax File Number is required',
67
- }),
68
- socialSecurityEmployerId: z.string().min(1, {
69
- message: 'National Insurance Employer ID is required',
70
- }),
71
- taxAdvancesRate: z
72
- .number()
73
- .min(0, {
74
- message: 'Advance Tax Rate must be at least 0',
75
- })
76
- .max(100, {
77
- message: 'Advance Tax Rate must be at most 100',
78
- }),
79
- taxAdvancesId: z.string().min(1, {
80
- message: 'Tax Advances ID is required',
81
- }),
82
82
  registrationDate: z.string().min(1, {
83
83
  message: 'Business Registration Start Date is required',
84
84
  }),
85
+ withholdingTaxAnnualIds: z.array(annualIdSchema),
86
+ withholdingTaxCompanyId: z.string().min(1, { message: 'Withholding Tax Company ID is required' }),
87
+ socialSecurityEmployerIds: z.array(annualIdSchema),
88
+ socialSecurityDeductionsId: z
89
+ .string()
90
+ .min(1, { message: 'Social Security Deductions ID is required' }),
91
+ taxAdvancesAnnualIds: z.array(annualIdSchema),
92
+ taxAdvancesRates: z.array(
93
+ z.object({
94
+ date: z.iso.date(),
95
+ rate: z
96
+ .number()
97
+ .min(0, { message: 'Rate must be at least 0' })
98
+ .max(100, { message: 'Rate must be at most 100' }),
99
+ }),
100
+ ),
85
101
  });
86
102
 
87
103
  type AdminBusinessFormValues = z.infer<typeof adminBusinessFormSchema>;
88
104
 
89
105
  function BusinessAdminSectionFragmentToFormValues(
90
106
  admin?: BusinessAdminSectionFragment,
91
- ): AdminBusinessFormValues {
107
+ ): Partial<AdminBusinessFormValues> {
92
108
  if (!admin || admin.__typename !== 'LtdFinancialEntity' || !admin.adminInfo) {
93
- return {} as AdminBusinessFormValues;
109
+ return {};
94
110
  }
95
111
 
96
112
  return {
97
- withholdingTaxBookNumber: admin.adminInfo.withholdingTaxBookNumber ?? '',
98
- withholdingTaxFileNumber: admin.adminInfo.withholdingTaxFileNumber ?? '',
99
- socialSecurityEmployerId: admin.adminInfo.socialSecurityEmployerId ?? '',
100
- taxAdvancesRate: admin.adminInfo.taxAdvancesRate ?? 0,
101
- taxAdvancesId: admin.adminInfo.taxAdvancesId ?? '',
102
- registrationDate: admin.adminInfo.registrationDate ?? '',
113
+ registrationDate: admin.adminInfo.registrationDate,
114
+ withholdingTaxAnnualIds: admin.adminInfo.withholdingTaxAnnualIds.sort(
115
+ (a, b) => b.year - a.year,
116
+ ),
117
+ withholdingTaxCompanyId: admin.adminInfo.withholdingTaxCompanyId ?? undefined,
118
+ socialSecurityEmployerIds: admin.adminInfo.socialSecurityEmployerIds.sort(
119
+ (a, b) => b.year - a.year,
120
+ ),
121
+ socialSecurityDeductionsId: admin.adminInfo.socialSecurityDeductionsId ?? undefined,
122
+ taxAdvancesAnnualIds: admin.adminInfo.taxAdvancesAnnualIds.sort((a, b) => b.year - a.year),
123
+ taxAdvancesRates: admin.adminInfo.taxAdvancesRates?.map(rate => ({
124
+ date: rate.date,
125
+ rate: rate.rate * 100,
126
+ })),
103
127
  };
104
128
  }
105
129
 
@@ -107,14 +131,17 @@ function convertFormDataToUpdateAdminBusinessInput(
107
131
  formData: Partial<AdminBusinessFormValues>,
108
132
  ): UpdateAdminBusinessInput {
109
133
  return {
110
- withholdingTaxBookNumber: formData.withholdingTaxBookNumber,
111
- withholdingTaxFileNumber: formData.withholdingTaxFileNumber,
112
- socialSecurityEmployerId: formData.socialSecurityEmployerId,
113
- taxAdvancesRate: formData.taxAdvancesRate,
114
- taxAdvancesId: formData.taxAdvancesId,
115
134
  registrationDate: formData.registrationDate
116
- ? (formatTimelessDateString(new Date(formData.registrationDate)) as TimelessDateString)
135
+ ? formatTimelessDateString(new Date(formData.registrationDate))
117
136
  : undefined,
137
+ withholdingTaxAnnualIds: formData.withholdingTaxAnnualIds,
138
+ withholdingTaxCompanyId: formData.withholdingTaxCompanyId,
139
+ socialSecurityEmployerIds: formData.socialSecurityEmployerIds,
140
+ taxAdvancesRates: formData.taxAdvancesRates?.map(rate => ({
141
+ date: rate.date,
142
+ rate: rate.rate / 100,
143
+ })) as { date: TimelessDateString; rate: number }[] | undefined,
144
+ taxAdvancesAnnualIds: formData.taxAdvancesAnnualIds,
118
145
  };
119
146
  }
120
147
 
@@ -166,6 +193,58 @@ export function AdminBusinessSection({ data, refetchBusiness }: Props): React.Re
166
193
  }
167
194
  }, [admin, form]);
168
195
 
196
+ // Make taxAdvancesAnnualIds a controlled field array using RHF's useFieldArray
197
+ const {
198
+ fields: taxAdvancesFields,
199
+ append: appendTaxAdvances,
200
+ remove: removeTaxAdvances,
201
+ } = useFieldArray({ control: form.control, name: 'taxAdvancesAnnualIds' as const });
202
+
203
+ // Make withholdingTaxAnnualIds a controlled field array using RHF's useFieldArray
204
+ const {
205
+ fields: withholdingTaxFields,
206
+ append: appendWithholdingTax,
207
+ remove: removeWithholdingTax,
208
+ } = useFieldArray({ control: form.control, name: 'withholdingTaxAnnualIds' as const });
209
+
210
+ // Make socialSecurityEmployerIds a controlled field array using RHF's useFieldArray
211
+ const {
212
+ fields: socialSecurityFields,
213
+ append: appendSocialSecurity,
214
+ remove: removeSocialSecurity,
215
+ } = useFieldArray({ control: form.control, name: 'socialSecurityEmployerIds' as const });
216
+
217
+ const annualIdActions = {
218
+ withholdingTaxAnnualIds: { append: appendWithholdingTax, remove: removeWithholdingTax },
219
+ taxAdvancesAnnualIds: { append: appendTaxAdvances, remove: removeTaxAdvances },
220
+ socialSecurityEmployerIds: { append: appendSocialSecurity, remove: removeSocialSecurity },
221
+ };
222
+
223
+ type AnnualIdField = keyof typeof annualIdActions;
224
+
225
+ const addAnnualId = (field: AnnualIdField) => {
226
+ annualIdActions[field].append({ year: new Date().getFullYear(), id: '' });
227
+ };
228
+
229
+ const removeAnnualId = (field: AnnualIdField, index: number): void => {
230
+ annualIdActions[field].remove(index);
231
+ };
232
+
233
+ // Make taxAdvancesRates a controlled field array using RHF's useFieldArray
234
+ const {
235
+ fields: taxAdvancesRateFields,
236
+ append: appendTaxAdvancesRate,
237
+ remove: removeTaxAdvancesRate,
238
+ } = useFieldArray({ control: form.control, name: 'taxAdvancesRates' as const });
239
+
240
+ const addRate = () => {
241
+ appendTaxAdvancesRate({ date: format(new Date(), 'yyyy-MM-dd'), rate: 0 });
242
+ };
243
+
244
+ const removeRate = (index: number): void => {
245
+ removeTaxAdvancesRate(index);
246
+ };
247
+
169
248
  return (
170
249
  <Card>
171
250
  <CardHeader>
@@ -187,13 +266,13 @@ export function AdminBusinessSection({ data, refetchBusiness }: Props): React.Re
187
266
 
188
267
  <FormField
189
268
  control={form.control}
190
- name="withholdingTaxBookNumber"
269
+ name="withholdingTaxCompanyId"
191
270
  render={({ field, fieldState }) => (
192
271
  <FormItem>
193
- <FormLabel>Book Number</FormLabel>
272
+ <FormLabel>Company Tax ID</FormLabel>
194
273
  <FormControl>
195
274
  <Input
196
- placeholder="Enter book number"
275
+ placeholder="Enter company ID"
197
276
  {...field}
198
277
  className={dirtyFieldMarker(fieldState)}
199
278
  />
@@ -203,67 +282,127 @@ export function AdminBusinessSection({ data, refetchBusiness }: Props): React.Re
203
282
  )}
204
283
  />
205
284
 
206
- <FormField
207
- control={form.control}
208
- name="withholdingTaxFileNumber"
209
- render={({ field, fieldState }) => (
210
- <FormItem>
211
- <FormLabel>File Number</FormLabel>
212
- <FormControl>
213
- <Input
214
- placeholder="Enter file number"
215
- {...field}
216
- className={dirtyFieldMarker(fieldState)}
217
- />
218
- </FormControl>
219
- <FormMessage />
220
- </FormItem>
221
- )}
222
- />
285
+ <div className="space-y-4">
286
+ <div className="flex items-center justify-between">
287
+ <Label>Annual IDs</Label>
288
+ <Button
289
+ type="button"
290
+ variant="outline"
291
+ size="sm"
292
+ onClick={() => addAnnualId('withholdingTaxAnnualIds')}
293
+ >
294
+ <Plus className="size-4" />
295
+ </Button>
296
+ </div>
297
+ <div className="space-y-3">
298
+ {withholdingTaxFields.map((field, index) => (
299
+ <div key={field.id} className="flex gap-2 items-start">
300
+ <div className="flex-1 grid grid-cols-2 gap-2">
301
+ <Input
302
+ placeholder="Year"
303
+ type="number"
304
+ {...form.register(`withholdingTaxAnnualIds.${index}.year`, {
305
+ valueAsNumber: true,
306
+ })}
307
+ />
308
+ <Input
309
+ placeholder="ID"
310
+ {...form.register(`withholdingTaxAnnualIds.${index}.id`)}
311
+ />
312
+ </div>
313
+ <Button
314
+ type="button"
315
+ variant="ghost"
316
+ size="icon"
317
+ onClick={() => removeAnnualId('withholdingTaxAnnualIds', index)}
318
+ >
319
+ <X className="size-4" />
320
+ </Button>
321
+ </div>
322
+ ))}
323
+ </div>
324
+ </div>
223
325
 
224
326
  <Separator className="md:col-span-2" />
225
327
 
226
328
  <h3 className="text-sm font-semibold text-foreground md:col-span-2">Tax Advances</h3>
227
329
 
228
- <FormField
229
- control={form.control}
230
- name="taxAdvancesId"
231
- render={({ field, fieldState }) => (
232
- <FormItem>
233
- <FormLabel>Identification number</FormLabel>
234
- <FormControl>
235
- <Input
236
- placeholder="Enter tax advances ID"
237
- {...field}
238
- className={dirtyFieldMarker(fieldState)}
239
- />
240
- </FormControl>
241
- <FormMessage />
242
- </FormItem>
243
- )}
244
- />
330
+ <div className="space-y-4">
331
+ <div className="flex items-center justify-between">
332
+ <Label>Annual IDs</Label>
333
+ <Button
334
+ type="button"
335
+ variant="outline"
336
+ size="sm"
337
+ onClick={() => addAnnualId('taxAdvancesAnnualIds')}
338
+ >
339
+ <Plus className="size-4" />
340
+ </Button>
341
+ </div>
342
+ <div className="space-y-3">
343
+ {taxAdvancesFields.map((field, index) => (
344
+ <div key={field.id} className="flex gap-2 items-start">
345
+ <div className="flex-1 grid grid-cols-2 gap-2">
346
+ <Input
347
+ placeholder="Year"
348
+ type="number"
349
+ {...form.register(`taxAdvancesAnnualIds.${index}.year`, {
350
+ valueAsNumber: true,
351
+ })}
352
+ />
353
+ <Input
354
+ placeholder="ID"
355
+ {...form.register(`taxAdvancesAnnualIds.${index}.id`)}
356
+ />
357
+ </div>
358
+ <Button
359
+ type="button"
360
+ variant="ghost"
361
+ size="icon"
362
+ onClick={() => removeAnnualId('taxAdvancesAnnualIds', index)}
363
+ >
364
+ <X className="size-4" />
365
+ </Button>
366
+ </div>
367
+ ))}
368
+ </div>
369
+ </div>
245
370
 
246
- <FormField
247
- control={form.control}
248
- name="taxAdvancesRate"
249
- render={({ field, fieldState }) => (
250
- <FormItem>
251
- <FormLabel>Tax Rate (%)</FormLabel>
252
- <FormControl>
253
- <Input
254
- type="number"
255
- step="0.01"
256
- min="0"
257
- max="100"
258
- placeholder="Enter tax rate"
259
- {...field}
260
- className={dirtyFieldMarker(fieldState)}
261
- />
262
- </FormControl>
263
- <FormMessage />
264
- </FormItem>
265
- )}
266
- />
371
+ <div className="space-y-4">
372
+ <div className="flex items-center justify-between">
373
+ <Label>Rates (%)</Label>
374
+ <Button type="button" variant="outline" size="sm" onClick={addRate}>
375
+ <Plus className="size-4" />
376
+ </Button>
377
+ </div>
378
+ <div className="space-y-3">
379
+ {taxAdvancesRateFields.map((field, index) => (
380
+ <div key={field.id} className="flex gap-2 items-start">
381
+ <div className="flex-1 grid grid-cols-2 gap-2">
382
+ <Input
383
+ placeholder="Date"
384
+ type="date"
385
+ {...form.register(`taxAdvancesRates.${index}.date`)}
386
+ />
387
+ <Input
388
+ placeholder="Rate"
389
+ {...form.register(`taxAdvancesRates.${index}.rate`, {
390
+ valueAsNumber: true,
391
+ })}
392
+ />
393
+ </div>
394
+ <Button
395
+ type="button"
396
+ variant="ghost"
397
+ size="icon"
398
+ onClick={() => removeRate(index)}
399
+ >
400
+ <X className="size-4" />
401
+ </Button>
402
+ </div>
403
+ ))}
404
+ </div>
405
+ </div>
267
406
 
268
407
  <Separator className="md:col-span-2" />
269
408
 
@@ -271,16 +410,15 @@ export function AdminBusinessSection({ data, refetchBusiness }: Props): React.Re
271
410
  Social Security
272
411
  </h3>
273
412
 
274
- {/* Social Security Employer ID */}
275
413
  <FormField
276
414
  control={form.control}
277
- name="socialSecurityEmployerId"
415
+ name="socialSecurityDeductionsId"
278
416
  render={({ field, fieldState }) => (
279
417
  <FormItem>
280
- <FormLabel>Employer Identifier</FormLabel>
418
+ <FormLabel>Deductions ID</FormLabel>
281
419
  <FormControl>
282
420
  <Input
283
- placeholder="Enter employer ID"
421
+ placeholder="Enter deductions ID"
284
422
  {...field}
285
423
  className={dirtyFieldMarker(fieldState)}
286
424
  />
@@ -290,6 +428,47 @@ export function AdminBusinessSection({ data, refetchBusiness }: Props): React.Re
290
428
  )}
291
429
  />
292
430
 
431
+ <div className="space-y-4">
432
+ <div className="flex items-center justify-between">
433
+ <Label>Annual Employer IDs</Label>
434
+ <Button
435
+ type="button"
436
+ variant="outline"
437
+ size="sm"
438
+ onClick={() => addAnnualId('socialSecurityEmployerIds')}
439
+ >
440
+ <Plus className="size-4" />
441
+ </Button>
442
+ </div>
443
+ <div className="space-y-3">
444
+ {socialSecurityFields.map((field, index) => (
445
+ <div key={field.id} className="flex gap-2 items-start">
446
+ <div className="flex-1 grid grid-cols-2 gap-2">
447
+ <Input
448
+ placeholder="Year"
449
+ type="number"
450
+ {...form.register(`socialSecurityEmployerIds.${index}.year`, {
451
+ valueAsNumber: true,
452
+ })}
453
+ />
454
+ <Input
455
+ placeholder="ID"
456
+ {...form.register(`socialSecurityEmployerIds.${index}.id`)}
457
+ />
458
+ </div>
459
+ <Button
460
+ type="button"
461
+ variant="ghost"
462
+ size="icon"
463
+ onClick={() => removeAnnualId('socialSecurityEmployerIds', index)}
464
+ >
465
+ <X className="size-4" />
466
+ </Button>
467
+ </div>
468
+ ))}
469
+ </div>
470
+ </div>
471
+
293
472
  <Separator className="md:col-span-2" />
294
473
 
295
474
  {/* Business Registration Start Date */}
@@ -130,7 +130,7 @@ export function ModifyContractDialog({ clientId, contract, contractId, onDone }:
130
130
  const { createContract, creating } = useCreateContract();
131
131
 
132
132
  // Only fetch if we don't have loader data
133
- const [{ data: fetchedContractData, fetching }, fetchContract] = useQuery({
133
+ const [{ data: fetchedContractData, fetching }] = useQuery({
134
134
  query: ContractsEditModalDocument,
135
135
  pause: !contractId || !isDialogOpen,
136
136
  variables: {
@@ -138,12 +138,6 @@ export function ModifyContractDialog({ clientId, contract, contractId, onDone }:
138
138
  },
139
139
  });
140
140
 
141
- useEffect(() => {
142
- if (isDialogOpen && contractId) {
143
- fetchContract();
144
- }
145
- }, [isDialogOpen, contractId, fetchContract]);
146
-
147
141
  const form = useForm<ContractFormValues>({
148
142
  resolver: zodResolver(contractFormSchema),
149
143
  defaultValues: contract || newContractDefaultValues,
@@ -6,5 +6,9 @@ type Props = {
6
6
  };
7
7
 
8
8
  export const DateCell = ({ timelessDate }: Props): ReactElement => {
9
- return <p className="text-sm font-medium">{new Date(timelessDate).toLocaleDateString()}</p>;
9
+ return (
10
+ <p className="text-sm font-medium">
11
+ {new Date(timelessDate).toLocaleDateString(undefined, { timeZone: 'UTC' })}
12
+ </p>
13
+ );
10
14
  };
@@ -123,7 +123,7 @@ export const columns: ColumnDef<ContractRow>[] = [
123
123
  <div className="flex flex-row gap-1 items-center">
124
124
  {row.original.msCloud && (
125
125
  <Link to={row.original.msCloud} target="_blank" rel="noreferrer" className="size-8">
126
- <Button variant="link" size="sm" disabled>
126
+ <Button variant="link" size="sm">
127
127
  <LinkIcon className="size-4" />
128
128
  </Button>
129
129
  </Link>
@@ -47,7 +47,7 @@ export function ContractsFilter({ table }: Props) {
47
47
  <Label>Product Type</Label>
48
48
  <Select
49
49
  onValueChange={value =>
50
- table.getColumn('product')?.setFilterValue(value === 'NULL' ? '' : value)
50
+ table.getColumn('product')?.setFilterValue(value === 'NULL' ? undefined : value)
51
51
  }
52
52
  value={table.getColumn('product')?.getFilterValue() as Product | ''}
53
53
  >
@@ -70,7 +70,9 @@ export function ContractsFilter({ table }: Props) {
70
70
  <Label>Billing Cycle</Label>
71
71
  <Select
72
72
  onValueChange={value =>
73
- table.getColumn('billingCycle')?.setFilterValue(value === 'NULL' ? '' : value)
73
+ table
74
+ .getColumn('billingCycle')
75
+ ?.setFilterValue(value === 'NULL' ? undefined : value)
74
76
  }
75
77
  value={table.getColumn('billingCycle')?.getFilterValue() as BillingCycle | ''}
76
78
  >
@@ -96,7 +98,7 @@ export function ContractsFilter({ table }: Props) {
96
98
  <Label>Subscription Plan</Label>
97
99
  <Select
98
100
  onValueChange={value =>
99
- table.getColumn('plan')?.setFilterValue(value === 'NULL' ? '' : value)
101
+ table.getColumn('plan')?.setFilterValue(value === 'NULL' ? undefined : value)
100
102
  }
101
103
  value={table.getColumn('plan')?.getFilterValue() as SubscriptionPlan | ''}
102
104
  >
@@ -122,7 +124,9 @@ export function ContractsFilter({ table }: Props) {
122
124
  onValueChange={value =>
123
125
  table
124
126
  .getColumn('isActive')
125
- ?.setFilterValue(value === 'NULL' ? '' : value === 'active' ? true : false)
127
+ ?.setFilterValue(
128
+ value === 'NULL' ? undefined : value === 'active' ? true : false,
129
+ )
126
130
  }
127
131
  value={convertBooleanToString(
128
132
  table.getColumn('isActive')?.getFilterValue() as boolean | undefined,
@@ -140,11 +144,6 @@ export function ContractsFilter({ table }: Props) {
140
144
  </SelectContent>
141
145
  </Select>
142
146
  </div>
143
-
144
- {/* <div>
145
- <FormLabel className="text-base">Active Status</FormLabel>
146
- <Switch checked={field.value} onCheckedChange={field.onChange} />
147
- </div> */}
148
147
  </div>
149
148
  </div>
150
149
  </DialogContent>
@@ -163,7 +163,6 @@ export const ContractsTable = ({ data }: Props): ReactElement => {
163
163
  });
164
164
 
165
165
  useEffect(() => {
166
- console.log('Row selection changed:', rowSelection);
167
166
  const selectedIndexes = Object.entries(rowSelection)
168
167
  .filter(([, value]) => !!value)
169
168
  .map(([key]) => Number(key));
@@ -113,7 +113,7 @@ export const IssueDocumentsModal = ({ contractIds }: Props): ReactElement => {
113
113
  return {
114
114
  ...field,
115
115
  ...watchFieldArray[index],
116
- id: field.client?.id,
116
+ id: field.id,
117
117
  };
118
118
  });
119
119
  }, [fields, watchFieldArray]);
@@ -127,8 +127,10 @@ export const IssueDocumentsModal = ({ contractIds }: Props): ReactElement => {
127
127
  </DialogTrigger>
128
128
  <DialogContent className="min-w-[90vw] w-full max-h-[90vh] overflow-y-auto">
129
129
  <DialogHeader>
130
- <DialogTitle>Filter Contracts</DialogTitle>
131
- <DialogDescription>Filter contracts based on various criteria</DialogDescription>
130
+ <DialogTitle>Issue Documents for Contracts</DialogTitle>
131
+ <DialogDescription>
132
+ Review and issue monthly documents for the selected contracts
133
+ </DialogDescription>
132
134
  </DialogHeader>
133
135
  {fetching ? (
134
136
  <AccounterLoader />
@@ -30,7 +30,7 @@ export const ContractsScreen = (): ReactElement => {
30
30
  }
31
31
 
32
32
  // Only fetch if we don't have loader data
33
- const [{ data, fetching }, fetchContracts] = useQuery({
33
+ const [{ data, fetching }] = useQuery({
34
34
  query: ContractsScreenDocument,
35
35
  pause: !adminId || !!loaderData,
36
36
  variables: {
@@ -50,7 +50,5 @@ export const ContractsScreen = (): ReactElement => {
50
50
  return <div>Contracts not found</div>;
51
51
  }
52
52
 
53
- return (
54
- <ContractsTable data={contractsData.contractsByAdmin} onChange={async () => fetchContracts()} />
55
- );
53
+ return <ContractsTable data={contractsData.contractsByAdmin} />;
56
54
  };