@accounter/client 0.0.8-alpha-20251030162201-d2f279aafe537912ec3546af855cbd3a38ac0f5c → 0.0.8-alpha-20251030164843-d2f490daba879840366288d1f62974ab25081876

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 (116) hide show
  1. package/CHANGELOG.md +27 -16
  2. package/dist/assets/{Checkbox-qEdmT4HE.js → Checkbox-dSmM5Kto.js} +2 -2
  3. package/dist/assets/{MultiSelect-Dm9mO7pJ.js → MultiSelect-BKzjkxRf.js} +1 -1
  4. package/dist/assets/{Progress-kr0gnfBa.js → Progress-CaCuNARE.js} +1 -1
  5. package/dist/assets/{Table-DnHfGe-y.js → Table-DxJ1YCr5.js} +1 -1
  6. package/dist/assets/{Typography-Cu3puAUK.js → Typography-rzf7AKzm.js} +1 -1
  7. package/dist/assets/{YearPickerInput-oa86GF4P.js → YearPickerInput-Bp2ytdrx.js} +1 -1
  8. package/dist/assets/{accordion-DLtMSqIv.js → accordion-B83CGJPM.js} +1 -1
  9. package/dist/assets/{accountant-approvals-DsL0uiBa.js → accountant-approvals-DRr7UYE4.js} +1 -1
  10. package/dist/assets/{accounter-table-BL_yrGIl.js → accounter-table-CLZmYCK0.js} +1 -1
  11. package/dist/assets/{addDays-DqZEDZy3.js → addDays-DbkSn4rN.js} +1 -1
  12. package/dist/assets/{all-charges-D3Xf-pEY.js → all-charges-Cn0oGAAS.js} +1 -1
  13. package/dist/assets/{arrow-up-down-DchtBEG4.js → arrow-up-down-kJRuABuk.js} +1 -1
  14. package/dist/assets/{building-2-ZTKteVvf.js → building-2-DAb5H_9e.js} +1 -1
  15. package/dist/assets/business-DeId1elJ.js +37 -0
  16. package/dist/assets/{business-extended-info-1mzdXJbs.js → business-extended-info-u-wZchjH.js} +4 -4
  17. package/dist/assets/{business-header-CJqfKV4d.js → business-header-vz6RQ5nZ.js} +1 -1
  18. package/dist/assets/{business-ledger-filters-BRB1r_DP.js → business-ledger-filters-DyyAMsOt.js} +1 -1
  19. package/dist/assets/{business-ledger-single-C8FIQJ8V.js → business-ledger-single-Cy7nqs_T.js} +1 -1
  20. package/dist/assets/business-trip-CA4-OIFH.js +1 -0
  21. package/dist/assets/{charge-Df3lWZH-.js → charge-DkSqluIG.js} +1 -1
  22. package/dist/assets/charges-filters-Djo_kWBf.js +1 -0
  23. package/dist/assets/{charges-ledger-validation-CtCBR3C-.js → charges-ledger-validation-DvCBQB1e.js} +1 -1
  24. package/dist/assets/{charges-table-CWbe3t13.js → charges-table-D1vDT-UP.js} +7 -7
  25. package/dist/assets/{chart-Cmm-jp0c.js → chart-BMSKXrwP.js} +1 -1
  26. package/dist/assets/contracts-ZJWgQOle.js +16 -0
  27. package/dist/assets/{data-table-pagination-fdOZTf64.js → data-table-pagination-BUpZwYMw.js} +2 -2
  28. package/dist/assets/{download-csv-button-CwK31swX.js → download-csv-button-tWswwko2.js} +1 -1
  29. package/dist/assets/edit-issue-document-modal-CHR5idQt.js +1 -0
  30. package/dist/assets/{editable-business-trip-Bjxkm9xV.js → editable-business-trip-D0UrHlFI.js} +2 -2
  31. package/dist/assets/eye-off-CGW7uC-c.js +6 -0
  32. package/dist/assets/{funnel-CMG4QvaK.js → funnel-Bmrsutts.js} +1 -1
  33. package/dist/assets/{index-CgokSIpu.js → index-2vL0dn5v.js} +1 -1
  34. package/dist/assets/index-B5HkjHjI.js +1 -0
  35. package/dist/assets/{index-Cw_aKL-8.js → index-BZ8AOwEl.js} +178 -173
  36. package/dist/assets/{index-CTatkdRy.js → index-Babx_Mc7.js} +2 -2
  37. package/dist/assets/{index-DLwMwjDQ.js → index-BnhjaCUg.js} +1 -1
  38. package/dist/assets/{index-xxe8M91O.js → index-Br0GTPfc.js} +2 -2
  39. package/dist/assets/index-BrSZxw1u.css +1 -0
  40. package/dist/assets/{index-DInU4RP4.js → index-C-VKA9Ok.js} +2 -2
  41. package/dist/assets/{index-CriBDqbK.js → index-C7cxxohd.js} +1 -1
  42. package/dist/assets/{index-C7oYbGGm.js → index-CUveXkuD.js} +1 -1
  43. package/dist/assets/index-CYX2yO-u.js +1 -0
  44. package/dist/assets/index-D1DOb6_Y.js +1 -0
  45. package/dist/assets/index-D7_jh5GD.js +1 -0
  46. package/dist/assets/index-DSuF8jdU.js +1 -0
  47. package/dist/assets/{index-CjC_SXIA.js → index-DTcOeWYo.js} +1 -1
  48. package/dist/assets/index-Dh1--D4F.js +1 -0
  49. package/dist/assets/{index-BEahR51x.js → index-Dkpu6Zhk.js} +2 -2
  50. package/dist/assets/index-DyH8FMHQ.js +1 -0
  51. package/dist/assets/index-HH5Rxplr.js +1 -0
  52. package/dist/assets/{index-B9CbQIGq.js → index-KBivZEq1.js} +2 -2
  53. package/dist/assets/{index-C_ZNQ0Zr.js → index-NS4xXWXV.js} +1 -1
  54. package/dist/assets/{index-6G62OvEh.js → index-cC755YI-.js} +1 -1
  55. package/dist/assets/{index-DFW4nqx8.js → index-dSI-XOHn.js} +7 -7
  56. package/dist/assets/index-h3vstU9e.js +1 -0
  57. package/dist/assets/{index-BZVrGMgV.js → index-tBA1vG1Y.js} +2 -2
  58. package/dist/assets/{index-jCPWIpdP.js → index-tMg1Ls6M.js} +1 -1
  59. package/dist/assets/{index.es-B_Bf6nNm.js → index.es-DNpMwt0n.js} +1 -1
  60. package/dist/assets/{insert-business-trip-modal-Ds3RIlmF.js → insert-business-trip-modal-4vXkqVnt.js} +2 -2
  61. package/dist/assets/issue-document-BoFHPotT.js +1 -0
  62. package/dist/assets/{list-plus-B3EB-dKe.js → list-plus-CDqpqAwS.js} +1 -1
  63. package/dist/assets/login-page-Bi8pRR_Y.js +1 -0
  64. package/dist/assets/{match-document-modal-Bo9pBr8W.js → match-document-modal-CETycNjj.js} +4 -4
  65. package/dist/assets/{missing-info-charges-BQYXI7bj.js → missing-info-charges-BPeEhfPv.js} +1 -1
  66. package/dist/assets/{modal-Pj_6bAFk.js → modal-8mlzJehM.js} +1 -1
  67. package/dist/assets/modify-contract-dialog-DWLEVQ1d.js +1 -0
  68. package/dist/assets/{page-layout-CVTeUSZp.js → page-layout-BfCdWwql.js} +1 -1
  69. package/dist/assets/{page-not-found-TvTAiAs4.js → page-not-found-DukC1kEI.js} +1 -1
  70. package/dist/assets/{panel-top-open-DzBY_TuM.js → panel-top-open-CpMFDJrl.js} +1 -1
  71. package/dist/assets/{pencil-BBmFhuZN.js → pencil-R8t4mFRO.js} +1 -1
  72. package/dist/assets/{report-commentary-row-Dqw62LLo.js → report-commentary-row-Byk41KMN.js} +1 -1
  73. package/dist/assets/{save-BW18gNVs.js → save-BjBw7mG5.js} +1 -1
  74. package/dist/assets/similar-transactions-modal-BPFaQ7dD.js +1 -0
  75. package/dist/assets/sub-dol6DnIB.js +1 -0
  76. package/dist/assets/subMonths-Cu51bw_I.js +1 -0
  77. package/dist/assets/{summary-Bbsq64IN.js → summary-Sj8NMKlv.js} +1 -1
  78. package/dist/assets/{toggle-expansion-button-BrKkZtGj.js → toggle-expansion-button-Buzq87-g.js} +1 -1
  79. package/dist/assets/tooltip-gvPoRI4e.js +1 -0
  80. package/dist/assets/{use-url-query-C0mVgO2i.js → use-url-query-DOEL3cY1.js} +1 -1
  81. package/dist/index.html +2 -2
  82. package/package.json +1 -1
  83. package/src/components/business/admin-business-section.tsx +103 -282
  84. package/src/components/clients/contracts/modify-contract-dialog.tsx +335 -253
  85. package/src/components/contracts/cells/client.tsx +24 -0
  86. package/src/components/contracts/cells/date.tsx +14 -0
  87. package/src/components/contracts/cells/index.ts +2 -0
  88. package/src/components/contracts/columns.tsx +182 -0
  89. package/src/components/contracts/contracts-filter.tsx +159 -0
  90. package/src/components/contracts/index.tsx +263 -0
  91. package/src/components/contracts/issue-documents-modal.tsx +236 -0
  92. package/src/components/layout/sidelinks.tsx +7 -0
  93. package/src/components/screens/businesses/clients/contracts/contracts.tsx +54 -0
  94. package/src/gql/gql.ts +27 -3
  95. package/src/gql/graphql.ts +73 -52
  96. package/src/router/config.tsx +13 -0
  97. package/src/router/routes.ts +1 -0
  98. package/dist/assets/business-CAcKSrnu.js +0 -37
  99. package/dist/assets/business-trip-DkTEY8b1.js +0 -1
  100. package/dist/assets/charges-filters-DUuY-N0H.js +0 -1
  101. package/dist/assets/index-BD4s2ucv.css +0 -1
  102. package/dist/assets/index-BFwWHKS1.js +0 -1
  103. package/dist/assets/index-BI0XToIk.js +0 -1
  104. package/dist/assets/index-BQb_C-JL.js +0 -1
  105. package/dist/assets/index-CJQlHnFs.js +0 -1
  106. package/dist/assets/index-Cm6Blkgf.js +0 -1
  107. package/dist/assets/index-DJLQkpmI.js +0 -6
  108. package/dist/assets/index-DcwGbXWr.js +0 -1
  109. package/dist/assets/index-Dlj3jpuW.js +0 -1
  110. package/dist/assets/index-iya2tfvn.js +0 -1
  111. package/dist/assets/issue-document-_iHCFO9h.js +0 -1
  112. package/dist/assets/login-page-BtT_TCEJ.js +0 -1
  113. package/dist/assets/similar-transactions-modal-B39q1NLa.js +0 -1
  114. package/dist/assets/sub-DOjETdwl.js +0 -1
  115. package/dist/assets/subMonths-DqeFZ4O6.js +0 -1
  116. package/dist/assets/tooltip-CbnJYNc4.js +0 -1
@@ -1,7 +1,8 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
2
  import { format } from 'date-fns';
3
- import { Plus, X } from 'lucide-react';
3
+ import { Edit, Plus, X } from 'lucide-react';
4
4
  import { useForm } from 'react-hook-form';
5
+ import { useQuery } from 'urql';
5
6
  import { z } from 'zod';
6
7
  import { Badge } from '@/components/ui/badge.js';
7
8
  import { Button } from '@/components/ui/button.js';
@@ -32,7 +33,14 @@ import {
32
33
  } from '@/components/ui/select.js';
33
34
  import { Switch } from '@/components/ui/switch.js';
34
35
  import { Textarea } from '@/components/ui/textarea.js';
35
- import { BillingCycle, Currency, DocumentType, Product, SubscriptionPlan } from '@/gql/graphql.js';
36
+ import {
37
+ BillingCycle,
38
+ ContractsEditModalDocument,
39
+ Currency,
40
+ DocumentType,
41
+ Product,
42
+ SubscriptionPlan,
43
+ } from '@/gql/graphql.js';
36
44
  import {
37
45
  getDocumentNameFromType,
38
46
  standardBillingCycle,
@@ -43,6 +51,30 @@ import { useCreateContract } from '@/hooks/use-create-contract.js';
43
51
  import { useUpdateContract } from '@/hooks/use-update-contract.js';
44
52
  import { zodResolver } from '@hookform/resolvers/zod';
45
53
 
54
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- used by codegen
55
+ /* GraphQL */ `
56
+ query ContractsEditModal($contractId: UUID!) {
57
+ contractsById(id: $contractId) {
58
+ id
59
+ startDate
60
+ endDate
61
+ purchaseOrders
62
+ amount {
63
+ raw
64
+ currency
65
+ }
66
+ product
67
+ msCloud
68
+ billingCycle
69
+ plan
70
+ isActive
71
+ remarks
72
+ documentType
73
+ operationsLimit
74
+ }
75
+ }
76
+ `;
77
+
46
78
  const contractFormSchema = z.object({
47
79
  id: z.uuid().optional(),
48
80
  // TODO: activate this field later. requires additional backend support
@@ -85,10 +117,11 @@ const newContractDefaultValues: ContractFormValues = {
85
117
  interface Props {
86
118
  clientId: string;
87
119
  contract?: ContractFormValues | null;
120
+ contractId?: string;
88
121
  onDone?: () => void;
89
122
  }
90
123
 
91
- export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
124
+ export function ModifyContractDialog({ clientId, contract, contractId, onDone }: Props) {
92
125
  const [isDialogOpen, setIsDialogOpen] = useState(false);
93
126
  const [editingContract, setEditingContract] = useState<ContractFormValues | null>(null);
94
127
  const [newPO, setNewPO] = useState('');
@@ -96,6 +129,15 @@ export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
96
129
  const { updateContract, updating } = useUpdateContract();
97
130
  const { createContract, creating } = useCreateContract();
98
131
 
132
+ // Only fetch if we don't have loader data
133
+ const [{ data: fetchedContractData, fetching }] = useQuery({
134
+ query: ContractsEditModalDocument,
135
+ pause: !contractId || !isDialogOpen,
136
+ variables: {
137
+ contractId: contractId ?? '',
138
+ },
139
+ });
140
+
99
141
  const form = useForm<ContractFormValues>({
100
142
  resolver: zodResolver(contractFormSchema),
101
143
  defaultValues: contract || newContractDefaultValues,
@@ -145,6 +187,32 @@ export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
145
187
  }
146
188
  }, [contract, form]);
147
189
 
190
+ useEffect(() => {
191
+ if (fetchedContractData?.contractsById) {
192
+ const fetchedContract = fetchedContractData.contractsById;
193
+ const formData: ContractFormValues = {
194
+ startDate: fetchedContract.startDate,
195
+ endDate: fetchedContract.endDate,
196
+ pos: fetchedContract.purchaseOrders,
197
+ paymentAmount: fetchedContract.amount.raw,
198
+ paymentCurrency: fetchedContract.amount.currency,
199
+ productType: fetchedContract.product ?? undefined,
200
+ msCloudLink: fetchedContract.msCloud?.toString() ?? undefined,
201
+ billingCycle: fetchedContract.billingCycle,
202
+ subscriptionPlan: fetchedContract.plan ?? undefined,
203
+ isActive: fetchedContract.isActive,
204
+ defaultRemark: fetchedContract.remarks ?? undefined,
205
+ defaultDocumentType: fetchedContract.documentType,
206
+ operationsLimit: fetchedContract.operationsLimit,
207
+ };
208
+ setEditingContract({
209
+ id: fetchedContract.id,
210
+ ...formData,
211
+ });
212
+ form.reset(formData);
213
+ }
214
+ }, [fetchedContractData, form]);
215
+
148
216
  const handleNew = () => {
149
217
  setEditingContract(null);
150
218
  form.reset(newContractDefaultValues);
@@ -207,8 +275,14 @@ export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
207
275
  <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
208
276
  <DialogTrigger asChild>
209
277
  <Button size="sm" onClick={handleNew}>
210
- <Plus className="h-4 w-4 mr-2" />
211
- New Contract
278
+ {contractId ? (
279
+ <Edit className="size-4" />
280
+ ) : (
281
+ <>
282
+ <Plus className="size-4 mr-2" />
283
+ New Contract
284
+ </>
285
+ )}
212
286
  </Button>
213
287
  </DialogTrigger>
214
288
  <DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
@@ -220,166 +294,260 @@ export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
220
294
  : 'Add a new contract with all required details'}
221
295
  </DialogDescription>
222
296
  </DialogHeader>
223
- <Form {...form}>
224
- <form onSubmit={form.handleSubmit(onSubmit)}>
225
- <div className="grid gap-4 py-4">
226
- <div className="grid gap-4 md:grid-cols-2">
227
- <FormField
228
- control={form.control}
229
- name="operationsLimit"
230
- render={({ field }) => (
231
- <FormItem>
232
- <FormLabel>Operations Limit</FormLabel>
233
- <FormControl>
234
- <Input type="number" placeholder="500" {...field} />
235
- </FormControl>
236
- <FormMessage />
237
- </FormItem>
238
- )}
239
- />
240
- <FormField
241
- control={form.control}
242
- name="pos"
243
- render={({ field }) => (
244
- <FormItem>
245
- <FormLabel>Purchase Orders</FormLabel>
246
- <div className="flex gap-2">
247
- <Input
248
- placeholder="Add PO..."
249
- value={newPO}
250
- onChange={e => setNewPO(e.target.value)}
251
- onKeyDown={e => {
252
- if (e.key === 'Enter') {
253
- e.preventDefault();
254
- addPO();
255
- }
256
- }}
257
- />
258
- <Button type="button" size="sm" onClick={addPO}>
259
- <Plus className="h-4 w-4" />
260
- </Button>
261
- </div>
262
- <div className="flex flex-wrap gap-2 mt-2">
263
- {field.value?.map((link, index) => (
264
- <Badge key={link} variant="secondary" className="gap-1 max-w-xs truncate">
265
- {link}
266
- {index === field.value.length - 1 && (
267
- <Button
268
- variant="ghost"
269
- size="icon"
270
- className="p-0 size-3"
271
- onClick={() => removePO(index)}
272
- >
273
- <X className="size-3 cursor-pointer flex-shrink-0" />
274
- </Button>
275
- )}
276
- </Badge>
277
- ))}
278
- </div>
279
- <FormMessage />
280
- </FormItem>
281
- )}
282
- />
283
- </div>
297
+ {fetching ? (
298
+ <>Fetching contract details...</>
299
+ ) : (
300
+ <Form {...form}>
301
+ <form onSubmit={form.handleSubmit(onSubmit)}>
302
+ <div className="grid gap-4 py-4">
303
+ <div className="grid gap-4 md:grid-cols-2">
304
+ <FormField
305
+ control={form.control}
306
+ name="operationsLimit"
307
+ render={({ field }) => (
308
+ <FormItem>
309
+ <FormLabel>Operations Limit</FormLabel>
310
+ <FormControl>
311
+ <Input type="number" placeholder="500" {...field} />
312
+ </FormControl>
313
+ <FormMessage />
314
+ </FormItem>
315
+ )}
316
+ />
317
+ <FormField
318
+ control={form.control}
319
+ name="pos"
320
+ render={({ field }) => (
321
+ <FormItem>
322
+ <FormLabel>Purchase Orders</FormLabel>
323
+ <div className="flex gap-2">
324
+ <Input
325
+ placeholder="Add PO..."
326
+ value={newPO}
327
+ onChange={e => setNewPO(e.target.value)}
328
+ onKeyDown={e => {
329
+ if (e.key === 'Enter') {
330
+ e.preventDefault();
331
+ addPO();
332
+ }
333
+ }}
334
+ />
335
+ <Button type="button" size="sm" onClick={addPO}>
336
+ <Plus className="h-4 w-4" />
337
+ </Button>
338
+ </div>
339
+ <div className="flex flex-wrap gap-2 mt-2">
340
+ {field.value?.map((link, index) => (
341
+ <Badge
342
+ key={link}
343
+ variant="secondary"
344
+ className="gap-1 max-w-xs truncate"
345
+ >
346
+ {link}
347
+ {index === field.value.length - 1 && (
348
+ <Button
349
+ variant="ghost"
350
+ size="icon"
351
+ className="p-0 size-3"
352
+ onClick={() => removePO(index)}
353
+ >
354
+ <X className="size-3 cursor-pointer flex-shrink-0" />
355
+ </Button>
356
+ )}
357
+ </Badge>
358
+ ))}
359
+ </div>
360
+ <FormMessage />
361
+ </FormItem>
362
+ )}
363
+ />
364
+ </div>
284
365
 
285
- <div className="grid gap-4 md:grid-cols-2">
286
- <FormField
287
- control={form.control}
288
- name="startDate"
289
- render={({ field: { onChange, ...field } }) => (
290
- <FormItem>
291
- <FormLabel>Start Date</FormLabel>
292
- <FormControl>
293
- <Input type="date" {...field} onInput={date => onChange(date)} />
294
- </FormControl>
295
- <FormMessage />
296
- </FormItem>
297
- )}
298
- />
299
- <FormField
300
- control={form.control}
301
- name="endDate"
302
- render={({ field: { onChange, ...field } }) => (
303
- <FormItem>
304
- <FormLabel>End Date</FormLabel>
305
- <FormControl>
306
- <Input type="date" {...field} onInput={date => onChange(date)} />
307
- </FormControl>
308
- <FormMessage />
309
- </FormItem>
310
- )}
311
- />
312
- </div>
366
+ <div className="grid gap-4 md:grid-cols-2">
367
+ <FormField
368
+ control={form.control}
369
+ name="startDate"
370
+ render={({ field: { onChange, ...field } }) => (
371
+ <FormItem>
372
+ <FormLabel>Start Date</FormLabel>
373
+ <FormControl>
374
+ <Input type="date" {...field} onInput={date => onChange(date)} />
375
+ </FormControl>
376
+ <FormMessage />
377
+ </FormItem>
378
+ )}
379
+ />
380
+ <FormField
381
+ control={form.control}
382
+ name="endDate"
383
+ render={({ field: { onChange, ...field } }) => (
384
+ <FormItem>
385
+ <FormLabel>End Date</FormLabel>
386
+ <FormControl>
387
+ <Input type="date" {...field} onInput={date => onChange(date)} />
388
+ </FormControl>
389
+ <FormMessage />
390
+ </FormItem>
391
+ )}
392
+ />
393
+ </div>
313
394
 
314
- <div className="grid gap-4 md:grid-cols-3">
315
- <FormField
316
- control={form.control}
317
- name="paymentAmount"
318
- render={({ field }) => (
319
- <FormItem className="md:col-span-2">
320
- <FormLabel>Payment Amount</FormLabel>
321
- <FormControl>
322
- <Input
323
- type="number"
324
- placeholder="24000"
325
- {...field}
326
- onChange={event => {
327
- field.onChange(
328
- event?.target.value ? Number(event?.target.value) : undefined,
329
- );
330
- }}
331
- />
332
- </FormControl>
333
- <FormMessage />
334
- </FormItem>
335
- )}
336
- />
337
- <FormField
338
- control={form.control}
339
- name="paymentCurrency"
340
- render={({ field }) => (
341
- <FormItem>
342
- <FormLabel>Currency</FormLabel>
343
- <Select onValueChange={field.onChange} defaultValue={field.value}>
395
+ <div className="grid gap-4 md:grid-cols-3">
396
+ <FormField
397
+ control={form.control}
398
+ name="paymentAmount"
399
+ render={({ field }) => (
400
+ <FormItem className="md:col-span-2">
401
+ <FormLabel>Payment Amount</FormLabel>
344
402
  <FormControl>
345
- <SelectTrigger>
346
- <SelectValue />
347
- </SelectTrigger>
403
+ <Input
404
+ type="number"
405
+ placeholder="24000"
406
+ {...field}
407
+ onChange={event => {
408
+ field.onChange(
409
+ event?.target.value ? Number(event?.target.value) : undefined,
410
+ );
411
+ }}
412
+ />
348
413
  </FormControl>
349
- <SelectContent>
350
- {Object.values(Currency).map(currency => (
351
- <SelectItem key={currency} value={currency}>
352
- {currency}
353
- </SelectItem>
354
- ))}
355
- </SelectContent>
356
- </Select>
357
- <FormMessage />
358
- </FormItem>
359
- )}
360
- />
361
- </div>
414
+ <FormMessage />
415
+ </FormItem>
416
+ )}
417
+ />
418
+ <FormField
419
+ control={form.control}
420
+ name="paymentCurrency"
421
+ render={({ field }) => (
422
+ <FormItem>
423
+ <FormLabel>Currency</FormLabel>
424
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
425
+ <FormControl>
426
+ <SelectTrigger>
427
+ <SelectValue />
428
+ </SelectTrigger>
429
+ </FormControl>
430
+ <SelectContent>
431
+ {Object.values(Currency).map(currency => (
432
+ <SelectItem key={currency} value={currency}>
433
+ {currency}
434
+ </SelectItem>
435
+ ))}
436
+ </SelectContent>
437
+ </Select>
438
+ <FormMessage />
439
+ </FormItem>
440
+ )}
441
+ />
442
+ </div>
443
+
444
+ <div className="grid gap-4 md:grid-cols-2">
445
+ <FormField
446
+ control={form.control}
447
+ name="productType"
448
+ render={({ field }) => (
449
+ <FormItem>
450
+ <FormLabel>Product Type</FormLabel>
451
+ <FormControl>
452
+ <Input placeholder="Cloud Services" {...field} />
453
+ </FormControl>
454
+ <FormMessage />
455
+ </FormItem>
456
+ )}
457
+ />
458
+ <FormField
459
+ control={form.control}
460
+ name="billingCycle"
461
+ render={({ field }) => (
462
+ <FormItem>
463
+ <FormLabel>Billing Cycle</FormLabel>
464
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
465
+ <FormControl>
466
+ <SelectTrigger>
467
+ <SelectValue />
468
+ </SelectTrigger>
469
+ </FormControl>
470
+ <SelectContent>
471
+ {Object.values(BillingCycle).map(cycle => (
472
+ <SelectItem key={cycle} value={cycle}>
473
+ {standardBillingCycle(cycle)}
474
+ </SelectItem>
475
+ ))}
476
+ </SelectContent>
477
+ </Select>
478
+ <FormMessage />
479
+ </FormItem>
480
+ )}
481
+ />
482
+ </div>
483
+
484
+ <div className="grid gap-4 md:grid-cols-2">
485
+ <FormField
486
+ control={form.control}
487
+ name="subscriptionPlan"
488
+ render={({ field }) => (
489
+ <FormItem>
490
+ <FormLabel>Subscription Plan</FormLabel>
491
+ <FormControl>
492
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
493
+ <FormControl>
494
+ <SelectTrigger>
495
+ <SelectValue />
496
+ </SelectTrigger>
497
+ </FormControl>
498
+ <SelectContent>
499
+ {Object.values(SubscriptionPlan).map(plan => (
500
+ <SelectItem key={plan} value={plan}>
501
+ {standardPlan(plan)}
502
+ </SelectItem>
503
+ ))}
504
+ </SelectContent>
505
+ </Select>
506
+ </FormControl>
507
+ <FormMessage />
508
+ </FormItem>
509
+ )}
510
+ />
511
+ <FormField
512
+ control={form.control}
513
+ name="isActive"
514
+ render={({ field }) => (
515
+ <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
516
+ <div className="space-y-0.5">
517
+ <FormLabel className="text-base">Active Status</FormLabel>
518
+ </div>
519
+ <FormControl>
520
+ <Switch checked={field.value} onCheckedChange={field.onChange} />
521
+ </FormControl>
522
+ </FormItem>
523
+ )}
524
+ />
525
+ </div>
362
526
 
363
- <div className="grid gap-4 md:grid-cols-2">
364
527
  <FormField
365
528
  control={form.control}
366
- name="productType"
529
+ name="msCloudLink"
367
530
  render={({ field }) => (
368
531
  <FormItem>
369
- <FormLabel>Product Type</FormLabel>
532
+ <FormLabel>MS Cloud Link</FormLabel>
370
533
  <FormControl>
371
- <Input placeholder="Cloud Services" {...field} />
534
+ <Input
535
+ type="url"
536
+ placeholder="https://portal.azure.com/contract-id"
537
+ {...field}
538
+ />
372
539
  </FormControl>
373
540
  <FormMessage />
374
541
  </FormItem>
375
542
  )}
376
543
  />
544
+
377
545
  <FormField
378
546
  control={form.control}
379
- name="billingCycle"
547
+ name="defaultDocumentType"
380
548
  render={({ field }) => (
381
549
  <FormItem>
382
- <FormLabel>Billing Cycle</FormLabel>
550
+ <FormLabel>Default Document Type</FormLabel>
383
551
  <Select onValueChange={field.onChange} defaultValue={field.value}>
384
552
  <FormControl>
385
553
  <SelectTrigger>
@@ -387,9 +555,9 @@ export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
387
555
  </SelectTrigger>
388
556
  </FormControl>
389
557
  <SelectContent>
390
- {Object.values(BillingCycle).map(cycle => (
391
- <SelectItem key={cycle} value={cycle}>
392
- {standardBillingCycle(cycle)}
558
+ {Object.values(DocumentType).map(type => (
559
+ <SelectItem key={type} value={type}>
560
+ {getDocumentNameFromType(type)}
393
561
  </SelectItem>
394
562
  ))}
395
563
  </SelectContent>
@@ -398,122 +566,36 @@ export function ModifyContractDialog({ clientId, contract, onDone }: Props) {
398
566
  </FormItem>
399
567
  )}
400
568
  />
401
- </div>
402
569
 
403
- <div className="grid gap-4 md:grid-cols-2">
404
570
  <FormField
405
571
  control={form.control}
406
- name="subscriptionPlan"
572
+ name="defaultRemark"
407
573
  render={({ field }) => (
408
574
  <FormItem>
409
- <FormLabel>Subscription Plan</FormLabel>
575
+ <FormLabel>Default Remark</FormLabel>
410
576
  <FormControl>
411
- <Select onValueChange={field.onChange} defaultValue={field.value}>
412
- <FormControl>
413
- <SelectTrigger>
414
- <SelectValue />
415
- </SelectTrigger>
416
- </FormControl>
417
- <SelectContent>
418
- {Object.values(SubscriptionPlan).map(plan => (
419
- <SelectItem key={plan} value={plan}>
420
- {standardPlan(plan)}
421
- </SelectItem>
422
- ))}
423
- </SelectContent>
424
- </Select>
577
+ <Textarea
578
+ placeholder="Enter default remark for this contract..."
579
+ rows={3}
580
+ {...field}
581
+ />
425
582
  </FormControl>
426
583
  <FormMessage />
427
584
  </FormItem>
428
585
  )}
429
586
  />
430
- <FormField
431
- control={form.control}
432
- name="isActive"
433
- render={({ field }) => (
434
- <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
435
- <div className="space-y-0.5">
436
- <FormLabel className="text-base">Active Status</FormLabel>
437
- </div>
438
- <FormControl>
439
- <Switch checked={field.value} onCheckedChange={field.onChange} />
440
- </FormControl>
441
- </FormItem>
442
- )}
443
- />
444
587
  </div>
445
-
446
- <FormField
447
- control={form.control}
448
- name="msCloudLink"
449
- render={({ field }) => (
450
- <FormItem>
451
- <FormLabel>MS Cloud Link</FormLabel>
452
- <FormControl>
453
- <Input
454
- type="url"
455
- placeholder="https://portal.azure.com/contract-id"
456
- {...field}
457
- />
458
- </FormControl>
459
- <FormMessage />
460
- </FormItem>
461
- )}
462
- />
463
-
464
- <FormField
465
- control={form.control}
466
- name="defaultDocumentType"
467
- render={({ field }) => (
468
- <FormItem>
469
- <FormLabel>Default Document Type</FormLabel>
470
- <Select onValueChange={field.onChange} defaultValue={field.value}>
471
- <FormControl>
472
- <SelectTrigger>
473
- <SelectValue />
474
- </SelectTrigger>
475
- </FormControl>
476
- <SelectContent>
477
- {Object.values(DocumentType).map(type => (
478
- <SelectItem key={type} value={type}>
479
- {getDocumentNameFromType(type)}
480
- </SelectItem>
481
- ))}
482
- </SelectContent>
483
- </Select>
484
- <FormMessage />
485
- </FormItem>
486
- )}
487
- />
488
-
489
- <FormField
490
- control={form.control}
491
- name="defaultRemark"
492
- render={({ field }) => (
493
- <FormItem>
494
- <FormLabel>Default Remark</FormLabel>
495
- <FormControl>
496
- <Textarea
497
- placeholder="Enter default remark for this contract..."
498
- rows={3}
499
- {...field}
500
- />
501
- </FormControl>
502
- <FormMessage />
503
- </FormItem>
504
- )}
505
- />
506
- </div>
507
- <DialogFooter>
508
- <Button type="button" variant="outline" onClick={() => setIsDialogOpen(false)}>
509
- Cancel
510
- </Button>
511
- <Button type="submit" disabled={creating || updating}>
512
- {editingContract ? 'Update Contract' : 'Create Contract'}
513
- </Button>
514
- </DialogFooter>
515
- </form>
516
- </Form>
588
+ <DialogFooter>
589
+ <Button type="button" variant="outline" onClick={() => setIsDialogOpen(false)}>
590
+ Cancel
591
+ </Button>
592
+ <Button type="submit" disabled={creating || updating}>
593
+ {editingContract ? 'Update Contract' : 'Create Contract'}
594
+ </Button>
595
+ </DialogFooter>
596
+ </form>
597
+ </Form>
598
+ )}
517
599
  </DialogContent>
518
600
  </Dialog>
519
601
  );