@hed-hog/finance 0.0.231 → 0.0.232

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.
@@ -15,5 +15,6 @@ export declare class CreateFinancialTitleDto {
15
15
  payment_channel?: string;
16
16
  description?: string;
17
17
  installments?: CreateFinancialInstallmentDto[];
18
+ attachment_file_ids?: number[];
18
19
  }
19
20
  //# sourceMappingURL=create-financial-title.dto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-financial-title.dto.d.ts","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":"AAcA,qBAAa,6BAA6B;IAUxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAS5B,QAAQ,EAAE,MAAM,CAAC;IAajB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,uBAAuB;IAOlC,eAAe,EAAE,MAAM,CAAC;IAKxB,SAAS,EAAE,MAAM,CAAC;IAUlB,eAAe,CAAC,EAAE,MAAM,CAAC;IAUzB,UAAU,CAAC,EAAE,MAAM,CAAC;IASpB,QAAQ,EAAE,MAAM,CAAC;IAajB,YAAY,EAAE,MAAM,CAAC;IAOrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAO7B,cAAc,CAAC,EAAE,MAAM,CAAC;IAOxB,eAAe,CAAC,EAAE,MAAM,CAAC;IAOzB,WAAW,CAAC,EAAE,MAAM,CAAC;IASrB,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAC;CAChD"}
1
+ {"version":3,"file":"create-financial-title.dto.d.ts","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":"AAcA,qBAAa,6BAA6B;IAUxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAS5B,QAAQ,EAAE,MAAM,CAAC;IAajB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,uBAAuB;IAOlC,eAAe,EAAE,MAAM,CAAC;IAKxB,SAAS,EAAE,MAAM,CAAC;IAUlB,eAAe,CAAC,EAAE,MAAM,CAAC;IAUzB,UAAU,CAAC,EAAE,MAAM,CAAC;IASpB,QAAQ,EAAE,MAAM,CAAC;IAajB,YAAY,EAAE,MAAM,CAAC;IAOrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAO7B,cAAc,CAAC,EAAE,MAAM,CAAC;IAOxB,eAAe,CAAC,EAAE,MAAM,CAAC;IAOzB,WAAW,CAAC,EAAE,MAAM,CAAC;IASrB,YAAY,CAAC,EAAE,6BAA6B,EAAE,CAAC;IAY/C,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC"}
@@ -125,4 +125,15 @@ __decorate([
125
125
  (0, class_transformer_1.Type)(() => CreateFinancialInstallmentDto),
126
126
  __metadata("design:type", Array)
127
127
  ], CreateFinancialTitleDto.prototype, "installments", void 0);
128
+ __decorate([
129
+ (0, class_validator_1.IsOptional)(),
130
+ (0, class_validator_1.IsArray)({
131
+ message: (args) => (0, api_locale_1.getLocaleText)('validation.attachmentFileIdsMustBeArray', args.value),
132
+ }),
133
+ (0, class_validator_1.IsInt)({
134
+ each: true,
135
+ message: (args) => (0, api_locale_1.getLocaleText)('validation.attachmentFileIdMustBeNumber', args.value),
136
+ }),
137
+ __metadata("design:type", Array)
138
+ ], CreateFinancialTitleDto.prototype, "attachment_file_ids", void 0);
128
139
  //# sourceMappingURL=create-financial-title.dto.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-financial-title.dto.js","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAoD;AACpD,yDAAyC;AACzC,qDAUyB;AAEzB,MAAa,6BAA6B;CAiCzC;AAjCD,sEAiCC;AAvBC;IATC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CAAC;IACD,IAAA,qBAAG,EAAC,CAAC,EAAE;QACN,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC/D,CAAC;;yEAC0B;AAS5B;IAPC,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,8BAA8B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5D,CACF;;+DACgB;AAajB;IAXC,IAAA,0BAAQ,EACP,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CACF;IACA,IAAA,qBAAG,EAAC,IAAI,EAAE;QACT,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC/D,CAAC;;6DACa;AAGjB,MAAa,uBAAuB;CA4FnC;AA5FD,0DA4FC;AArFC;IANC,IAAA,0BAAQ,EAAC;QACR,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAChF,CAAC;IACD,IAAA,4BAAU,EAAC;QACV,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,0BAAa,EAAC,6BAA6B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5E,CAAC;;gEACsB;AAKxB;IAHC,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,0BAAa,EAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,CAAC;KAChF,CAAC;;0DACgB;AAUlB;IARC,IAAA,4BAAU,GAAE;IACZ,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,qCAAqC,EAAE,IAAI,CAAC,KAAK,CAAC;KACnE,CACF;;gEACwB;AAUzB;IARC,IAAA,4BAAU,GAAE;IACZ,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,gCAAgC,EAAE,IAAI,CAAC,KAAK,CAAC;KAC9D,CACF;;2DACmB;AASpB;IAPC,IAAA,8BAAY,EACX,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,8BAA8B,EAAE,IAAI,CAAC,KAAK,CAAC;KAC5D,CACF;;yDACgB;AAajB;IAXC,IAAA,0BAAQ,EACP,EAAE,EACF;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,oCAAoC,EAAE,IAAI,CAAC,KAAK,CAAC;KAClE,CACF;IACA,IAAA,qBAAG,EAAC,IAAI,EAAE;QACT,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,2BAA2B,EAAE,IAAI,CAAC,KAAK,CAAC;KACzD,CAAC;;6DACmB;AAOrB;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,0CAA0C,EAAE,IAAI,CAAC,KAAK,CAAC;KACxE,CAAC;;oEAC2B;AAO7B;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,uBAAK,EAAC;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,qCAAqC,EAAE,IAAI,CAAC,KAAK,CAAC;KACnE,CAAC;;+DACsB;AAOxB;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,EAAC;QACR,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,uCAAuC,EAAE,IAAI,CAAC,KAAK,CAAC;KACrE,CAAC;;gEACuB;AAOzB;IALC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,EAAC;QACR,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,oCAAoC,EAAE,IAAI,CAAC,KAAK,CAAC;KAClE,CAAC;;4DACmB;AASrB;IAPC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,EAAC;QACP,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAChB,IAAA,0BAAa,EAAC,oCAAoC,EAAE,IAAI,CAAC,KAAK,CAAC;KAClE,CAAC;IACD,IAAA,gCAAc,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9B,IAAA,wBAAI,EAAC,GAAG,EAAE,CAAC,6BAA6B,CAAC;;6DACK"}
1
+ {"version":3,"file":"create-financial-title.dto.js","sourceRoot":"","sources":["../../src/dto/create-financial-title.dto.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,7 @@ import {
21
21
  import { Input } from '@/components/ui/input';
22
22
  import { InputMoney } from '@/components/ui/input-money';
23
23
  import { Money } from '@/components/ui/money';
24
+ import { Progress } from '@/components/ui/progress';
24
25
  import {
25
26
  Select,
26
27
  SelectContent,
@@ -96,6 +97,28 @@ function NovoTituloSheet({
96
97
  }) {
97
98
  const { request, showToastHandler } = useApp();
98
99
  const [open, setOpen] = useState(false);
100
+ const [uploadedFileId, setUploadedFileId] = useState<number | null>(null);
101
+ const [uploadedFileName, setUploadedFileName] = useState('');
102
+ const [isUploadingFile, setIsUploadingFile] = useState(false);
103
+ const [uploadProgress, setUploadProgress] = useState(0);
104
+
105
+ const normalizeFilenameForDisplay = (filename: string) => {
106
+ if (!filename) {
107
+ return filename;
108
+ }
109
+
110
+ if (!/Ã.|Â.|â[\u0080-\u00BF]/.test(filename)) {
111
+ return filename;
112
+ }
113
+
114
+ try {
115
+ const bytes = Uint8Array.from(filename, (char) => char.charCodeAt(0));
116
+ const decoded = new TextDecoder('utf-8').decode(bytes);
117
+ return /Ã.|Â.|â[\u0080-\u00BF]/.test(decoded) ? filename : decoded;
118
+ } catch {
119
+ return filename;
120
+ }
121
+ };
99
122
 
100
123
  const form = useForm<NewTitleFormValues>({
101
124
  resolver: zodResolver(newTitleFormSchema),
@@ -133,11 +156,14 @@ function NovoTituloSheet({
133
156
  : undefined,
134
157
  payment_channel: values.metodo || undefined,
135
158
  description: values.descricao?.trim() || undefined,
159
+ attachment_file_ids: uploadedFileId ? [uploadedFileId] : undefined,
136
160
  },
137
161
  });
138
162
 
139
163
  await onCreated();
140
164
  form.reset();
165
+ setUploadedFileId(null);
166
+ setUploadedFileName('');
141
167
  setOpen(false);
142
168
  showToastHandler?.('success', 'Título criado com sucesso');
143
169
  } catch {
@@ -147,9 +173,83 @@ function NovoTituloSheet({
147
173
 
148
174
  const handleCancel = () => {
149
175
  form.reset();
176
+ setUploadedFileId(null);
177
+ setUploadedFileName('');
178
+ setUploadProgress(0);
150
179
  setOpen(false);
151
180
  };
152
181
 
182
+ const uploadRelatedFile = async (file: File) => {
183
+ setIsUploadingFile(true);
184
+ setUploadProgress(0);
185
+
186
+ try {
187
+ const formData = new FormData();
188
+ formData.append('file', file);
189
+ formData.append('destination', 'finance/titles');
190
+
191
+ const { data } = await request<{ id: number; filename: string }>({
192
+ url: '/file',
193
+ method: 'POST',
194
+ data: formData,
195
+ headers: {
196
+ 'Content-Type': 'multipart/form-data',
197
+ },
198
+ onUploadProgress: (event) => {
199
+ if (!event.total) {
200
+ return;
201
+ }
202
+
203
+ const progress = Math.round((event.loaded * 100) / event.total);
204
+ setUploadProgress(progress);
205
+ },
206
+ });
207
+
208
+ if (!data?.id) {
209
+ throw new Error('Arquivo inválido');
210
+ }
211
+
212
+ setUploadedFileId(data.id);
213
+ setUploadedFileName(
214
+ normalizeFilenameForDisplay(data.filename || file.name)
215
+ );
216
+ setUploadProgress(100);
217
+ showToastHandler?.('success', 'Arquivo relacionado com sucesso');
218
+ } catch {
219
+ setUploadedFileId(null);
220
+ setUploadedFileName('');
221
+ setUploadProgress(0);
222
+ showToastHandler?.('error', 'Não foi possível enviar o arquivo');
223
+ } finally {
224
+ setIsUploadingFile(false);
225
+ }
226
+ };
227
+
228
+ const parseDateToIso = (value: string) => {
229
+ const sanitized = value.trim();
230
+
231
+ if (/^\d{4}-\d{2}-\d{2}$/.test(sanitized)) {
232
+ return sanitized;
233
+ }
234
+
235
+ const br = sanitized.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
236
+ if (br) {
237
+ return `${br[3]}-${br[2]}-${br[1]}`;
238
+ }
239
+
240
+ return '';
241
+ };
242
+
243
+ const parseMoneyToNumber = (value: string) => {
244
+ const normalized = value
245
+ .replace(/\s/g, '')
246
+ .replace(/\./g, '')
247
+ .replace(',', '.');
248
+
249
+ const parsed = Number(normalized);
250
+ return Number.isFinite(parsed) ? parsed : 0;
251
+ };
252
+
153
253
  return (
154
254
  <Sheet open={open} onOpenChange={setOpen}>
155
255
  <SheetTrigger asChild>
@@ -166,6 +266,41 @@ function NovoTituloSheet({
166
266
  <Form {...form}>
167
267
  <form className="px-4" onSubmit={form.handleSubmit(handleSubmit)}>
168
268
  <div className="grid gap-4">
269
+ <div className="grid gap-2">
270
+ <FormLabel>Arquivo da fatura (opcional)</FormLabel>
271
+ <div className="flex flex-col gap-2 sm:flex-row sm:items-center">
272
+ <Input
273
+ type="file"
274
+ accept=".pdf,.png,.jpg,.jpeg,.xml,.txt"
275
+ onChange={(event) => {
276
+ const file = event.target.files?.[0];
277
+ if (!file) {
278
+ return;
279
+ }
280
+
281
+ setUploadedFileId(null);
282
+ setUploadedFileName('');
283
+ setUploadProgress(0);
284
+ void uploadRelatedFile(file);
285
+ }}
286
+ disabled={isUploadingFile || form.formState.isSubmitting}
287
+ />
288
+ </div>
289
+ {isUploadingFile && (
290
+ <div className="space-y-1">
291
+ <Progress value={uploadProgress} className="h-2" />
292
+ <p className="text-xs text-muted-foreground">
293
+ Upload em andamento: {uploadProgress}%
294
+ </p>
295
+ </div>
296
+ )}
297
+ {uploadedFileId && (
298
+ <p className="text-xs text-muted-foreground">
299
+ Arquivo relacionado: {uploadedFileName}
300
+ </p>
301
+ )}
302
+ </div>
303
+
169
304
  <FormField
170
305
  control={form.control}
171
306
  name="documento"
@@ -188,7 +323,7 @@ function NovoTituloSheet({
188
323
  <FormLabel>{t('fields.supplier')}</FormLabel>
189
324
  <Select value={field.value} onValueChange={field.onChange}>
190
325
  <FormControl>
191
- <SelectTrigger>
326
+ <SelectTrigger className="w-full">
192
327
  <SelectValue placeholder={t('common.select')} />
193
328
  </SelectTrigger>
194
329
  </FormControl>
@@ -276,7 +411,7 @@ function NovoTituloSheet({
276
411
  <FormLabel>{t('fields.category')}</FormLabel>
277
412
  <Select value={field.value} onValueChange={field.onChange}>
278
413
  <FormControl>
279
- <SelectTrigger>
414
+ <SelectTrigger className="w-full">
280
415
  <SelectValue placeholder={t('common.select')} />
281
416
  </SelectTrigger>
282
417
  </FormControl>
@@ -303,7 +438,7 @@ function NovoTituloSheet({
303
438
  <FormLabel>{t('fields.costCenter')}</FormLabel>
304
439
  <Select value={field.value} onValueChange={field.onChange}>
305
440
  <FormControl>
306
- <SelectTrigger>
441
+ <SelectTrigger className="w-full">
307
442
  <SelectValue placeholder={t('common.select')} />
308
443
  </SelectTrigger>
309
444
  </FormControl>
@@ -328,7 +463,7 @@ function NovoTituloSheet({
328
463
  <FormLabel>{t('fields.paymentMethod')}</FormLabel>
329
464
  <Select value={field.value} onValueChange={field.onChange}>
330
465
  <FormControl>
331
- <SelectTrigger>
466
+ <SelectTrigger className="w-full">
332
467
  <SelectValue placeholder={t('common.select')} />
333
468
  </SelectTrigger>
334
469
  </FormControl>
@@ -285,37 +285,64 @@ function NovaContaSheet({
285
285
  />
286
286
  </div>
287
287
 
288
- <FormField
289
- control={form.control}
290
- name="tipo"
291
- render={({ field }) => (
292
- <FormItem>
293
- <FormLabel>{t('fields.type')}</FormLabel>
294
- <Select value={field.value} onValueChange={field.onChange}>
288
+ <div className="grid grid-cols-2 gap-4">
289
+ <FormField
290
+ control={form.control}
291
+ name="tipo"
292
+ render={({ field }) => (
293
+ <FormItem>
294
+ <FormLabel>{t('fields.type')}</FormLabel>
295
+ <Select
296
+ value={field.value}
297
+ onValueChange={field.onChange}
298
+ >
299
+ <FormControl>
300
+ <SelectTrigger className="w-full">
301
+ <SelectValue placeholder={t('common.select')} />
302
+ </SelectTrigger>
303
+ </FormControl>
304
+ <SelectContent>
305
+ <SelectItem value="corrente">
306
+ {t('types.corrente')}
307
+ </SelectItem>
308
+ <SelectItem value="poupanca">
309
+ {t('types.poupanca')}
310
+ </SelectItem>
311
+ <SelectItem value="investimento">
312
+ {t('types.investimento')}
313
+ </SelectItem>
314
+ <SelectItem value="caixa">
315
+ {t('types.caixa')}
316
+ </SelectItem>
317
+ </SelectContent>
318
+ </Select>
319
+ <FormMessage />
320
+ </FormItem>
321
+ )}
322
+ />
323
+
324
+ <FormField
325
+ control={form.control}
326
+ name="saldoInicial"
327
+ render={({ field }) => (
328
+ <FormItem>
329
+ <FormLabel>{t('fields.initialBalance')}</FormLabel>
295
330
  <FormControl>
296
- <SelectTrigger>
297
- <SelectValue placeholder={t('common.select')} />
298
- </SelectTrigger>
331
+ <InputMoney
332
+ ref={field.ref}
333
+ name={field.name}
334
+ value={field.value}
335
+ onBlur={field.onBlur}
336
+ onValueChange={(value) => field.onChange(value ?? 0)}
337
+ placeholder="0,00"
338
+ disabled={!!editingAccount}
339
+ />
299
340
  </FormControl>
300
- <SelectContent>
301
- <SelectItem value="corrente">
302
- {t('types.corrente')}
303
- </SelectItem>
304
- <SelectItem value="poupanca">
305
- {t('types.poupanca')}
306
- </SelectItem>
307
- <SelectItem value="investimento">
308
- {t('types.investimento')}
309
- </SelectItem>
310
- <SelectItem value="caixa">
311
- {t('types.caixa')}
312
- </SelectItem>
313
- </SelectContent>
314
- </Select>
315
- <FormMessage />
316
- </FormItem>
317
- )}
318
- />
341
+ <FormMessage />
342
+ </FormItem>
343
+ )}
344
+ />
345
+ </div>
319
346
 
320
347
  <FormField
321
348
  control={form.control}
@@ -334,28 +361,6 @@ function NovaContaSheet({
334
361
  </FormItem>
335
362
  )}
336
363
  />
337
-
338
- <FormField
339
- control={form.control}
340
- name="saldoInicial"
341
- render={({ field }) => (
342
- <FormItem>
343
- <FormLabel>{t('fields.initialBalance')}</FormLabel>
344
- <FormControl>
345
- <InputMoney
346
- ref={field.ref}
347
- name={field.name}
348
- value={field.value}
349
- onBlur={field.onBlur}
350
- onValueChange={(value) => field.onChange(value ?? 0)}
351
- placeholder="0,00"
352
- disabled={!!editingAccount}
353
- />
354
- </FormControl>
355
- <FormMessage />
356
- </FormItem>
357
- )}
358
- />
359
364
  </div>
360
365
 
361
366
  <div className="flex justify-end gap-2 pt-4">
@@ -412,6 +417,7 @@ export default function ContasBancariasPage() {
412
417
  },
413
418
  placeholderData: [],
414
419
  });
420
+ const accounts = contasBancarias ?? [];
415
421
 
416
422
  const tipoConfig = {
417
423
  corrente: { label: t('types.corrente'), icon: Building2 },
@@ -420,11 +426,11 @@ export default function ContasBancariasPage() {
420
426
  caixa: { label: t('types.caixa'), icon: Wallet },
421
427
  };
422
428
 
423
- const saldoTotal = contasBancarias
429
+ const saldoTotal = accounts
424
430
  .filter((c) => c.ativo)
425
431
  .reduce((acc, c) => acc + c.saldoAtual, 0);
426
432
 
427
- const saldoConciliadoTotal = contasBancarias
433
+ const saldoConciliadoTotal = accounts
428
434
  .filter((c) => c.ativo)
429
435
  .reduce((acc, c) => acc + c.saldoConciliado, 0);
430
436
 
@@ -522,7 +528,7 @@ export default function ContasBancariasPage() {
522
528
  </div>
523
529
  <p className="text-xs text-muted-foreground">
524
530
  {t('cards.activeAccounts', {
525
- count: contasBancarias.filter((c) => c.ativo).length,
531
+ count: accounts.filter((c) => c.ativo).length,
526
532
  })}
527
533
  </p>
528
534
  </CardContent>
@@ -547,7 +553,7 @@ export default function ContasBancariasPage() {
547
553
  </div>
548
554
 
549
555
  <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
550
- {contasBancarias.map((conta) => {
556
+ {accounts.map((conta) => {
551
557
  const tipo =
552
558
  tipoConfig[conta.tipo as keyof typeof tipoConfig] ||
553
559
  tipoConfig.corrente;
@@ -563,14 +569,25 @@ export default function ContasBancariasPage() {
563
569
  <TipoIcon className="h-5 w-5" />
564
570
  </div>
565
571
  <div>
566
- <CardTitle className="text-base">{conta.banco}</CardTitle>
567
- <CardDescription>
568
- {conta.agencia !== '-'
569
- ? t('accountCard.bankAccount', {
572
+ <div className="flex gap-4 items-center">
573
+ <CardTitle className="text-base">
574
+ {conta.banco}
575
+ </CardTitle>
576
+ {conta.descricao && (
577
+ <span className="block text-muted-foreground text-xs">
578
+ {conta.descricao}
579
+ </span>
580
+ )}
581
+ </div>
582
+ <CardDescription className="space-y-0.5">
583
+ {conta.agencia !== '-' && (
584
+ <span className="block">
585
+ {t('accountCard.bankAccount', {
570
586
  agency: conta.agencia,
571
587
  account: conta.conta,
572
- })
573
- : conta.descricao}
588
+ })}
589
+ </span>
590
+ )}
574
591
  </CardDescription>
575
592
  </div>
576
593
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.231",
3
+ "version": "0.0.232",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -12,10 +12,10 @@
12
12
  "@hed-hog/api-locale": "0.0.11",
13
13
  "@hed-hog/api-prisma": "0.0.4",
14
14
  "@hed-hog/api-pagination": "0.0.5",
15
- "@hed-hog/tag": "0.0.223",
16
- "@hed-hog/api": "0.0.3",
17
15
  "@hed-hog/api-types": "0.0.1",
18
- "@hed-hog/contact": "0.0.223"
16
+ "@hed-hog/api": "0.0.3",
17
+ "@hed-hog/tag": "0.0.232",
18
+ "@hed-hog/contact": "0.0.232"
19
19
  },
20
20
  "exports": {
21
21
  ".": {
@@ -139,4 +139,16 @@ export class CreateFinancialTitleDto {
139
139
  @ValidateNested({ each: true })
140
140
  @Type(() => CreateFinancialInstallmentDto)
141
141
  installments?: CreateFinancialInstallmentDto[];
142
+
143
+ @IsOptional()
144
+ @IsArray({
145
+ message: (args) =>
146
+ getLocaleText('validation.attachmentFileIdsMustBeArray', args.value),
147
+ })
148
+ @IsInt({
149
+ each: true,
150
+ message: (args) =>
151
+ getLocaleText('validation.attachmentFileIdMustBeNumber', args.value),
152
+ })
153
+ attachment_file_ids?: number[];
142
154
  }