@snksergio/design-system 0.62.0 → 0.63.0

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 (135) hide show
  1. package/dist-lib/ai/blocos/chart/budget-breakdown.tsx +174 -0
  2. package/dist-lib/ai/blocos/indice.md +43 -0
  3. package/dist-lib/ai/blocos/paneldetail/detalhe-com-tabela.tsx +450 -0
  4. package/dist-lib/ai/blocos/paneldetail/detalhe-de-tarefa-com-abas.tsx +570 -0
  5. package/dist-lib/ai/blocos/paneldetail/detalhe-do-registro.tsx +555 -0
  6. package/dist-lib/ai/exemplos/app-shell/app-shell-example.tsx +140 -0
  7. package/dist-lib/ai/exemplos/app-shell/index.ts +3 -0
  8. package/dist-lib/ai/exemplos/app-shell/nav-data.ts +97 -0
  9. package/dist-lib/ai/exemplos/app-shell/routes.tsx +75 -0
  10. package/dist-lib/ai/exemplos/chat/chat-screen.tsx +152 -0
  11. package/dist-lib/ai/exemplos/chat/chat-v2-mocks.ts +171 -0
  12. package/dist-lib/ai/exemplos/chat/chat-v2.styles.ts +23 -0
  13. package/dist-lib/ai/exemplos/chat/chat-v2.types.ts +81 -0
  14. package/dist-lib/ai/exemplos/chat/components/ChannelDot/channel-dot.tsx +28 -0
  15. package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/conversation-actions-menu.tsx +83 -0
  16. package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/index.ts +4 -0
  17. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.styles.ts +22 -0
  18. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.tsx +203 -0
  19. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.types.ts +10 -0
  20. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/index.ts +2 -0
  21. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.styles.ts +55 -0
  22. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.tsx +52 -0
  23. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.types.ts +7 -0
  24. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/index.ts +2 -0
  25. package/dist-lib/ai/exemplos/chat/components/DateSeparator/date-separator.tsx +18 -0
  26. package/dist-lib/ai/exemplos/chat/components/DetailField/detail-field.tsx +23 -0
  27. package/dist-lib/ai/exemplos/chat/components/DetailSection/detail-section.tsx +41 -0
  28. package/dist-lib/ai/exemplos/chat/components/DetailSection/index.ts +1 -0
  29. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.styles.ts +30 -0
  30. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.tsx +142 -0
  31. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.types.ts +16 -0
  32. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/index.ts +5 -0
  33. package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.styles.ts +37 -0
  34. package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.tsx +45 -0
  35. package/dist-lib/ai/exemplos/chat/components/FilterRow/index.ts +1 -0
  36. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.styles.ts +27 -0
  37. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.tsx +66 -0
  38. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.types.ts +13 -0
  39. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-rail.tsx +38 -0
  40. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/index.ts +6 -0
  41. package/dist-lib/ai/exemplos/chat/components/MessageBubble/index.ts +2 -0
  42. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.styles.ts +37 -0
  43. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.tsx +29 -0
  44. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.types.ts +5 -0
  45. package/dist-lib/ai/exemplos/chat/components/PersonAvatar/index.ts +5 -0
  46. package/dist-lib/ai/exemplos/chat/components/PersonAvatar/person-avatar.tsx +31 -0
  47. package/dist-lib/ai/exemplos/chat/components/QueueColumn/index.ts +2 -0
  48. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.styles.ts +19 -0
  49. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.tsx +140 -0
  50. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.types.ts +13 -0
  51. package/dist-lib/ai/exemplos/chat/components/RailItem/index.ts +1 -0
  52. package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.styles.ts +30 -0
  53. package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.tsx +42 -0
  54. package/dist-lib/ai/exemplos/chat/hooks/use-resizable.ts +98 -0
  55. package/dist-lib/ai/exemplos/chat/index.ts +1 -0
  56. package/dist-lib/ai/exemplos/clientes/_table-data.ts +59 -0
  57. package/dist-lib/ai/exemplos/clientes/clientes-screen.tsx +505 -0
  58. package/dist-lib/ai/exemplos/clientes/clientes-showcase-mocks.ts +117 -0
  59. package/dist-lib/ai/exemplos/clientes/clientes-showcase.styles.ts +13 -0
  60. package/dist-lib/ai/exemplos/clientes/clientes-showcase.types.ts +16 -0
  61. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.styles.ts +28 -0
  62. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.tsx +303 -0
  63. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.types.ts +14 -0
  64. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/index.ts +2 -0
  65. package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/index.ts +2 -0
  66. package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
  67. package/dist-lib/ai/exemplos/clientes/index.ts +1 -0
  68. package/dist-lib/ai/exemplos/edit-page/components/StepNav.tsx +81 -0
  69. package/dist-lib/ai/exemplos/edit-page/components/section-card.tsx +85 -0
  70. package/dist-lib/ai/exemplos/edit-page/edit-page-screen.tsx +234 -0
  71. package/dist-lib/ai/exemplos/edit-page/index.ts +1 -0
  72. package/dist-lib/ai/exemplos/finance/_table-data.ts +57 -0
  73. package/dist-lib/ai/exemplos/finance/clientes-financeiro-mocks.ts +227 -0
  74. package/dist-lib/ai/exemplos/finance/clientes-financeiro.types.ts +75 -0
  75. package/dist-lib/ai/exemplos/finance/clientes-showcase-mocks.ts +117 -0
  76. package/dist-lib/ai/exemplos/finance/clientes-showcase.styles.ts +13 -0
  77. package/dist-lib/ai/exemplos/finance/clientes-showcase.types.ts +16 -0
  78. package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/editar-finance-drawer.tsx +241 -0
  79. package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/index.ts +5 -0
  80. package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/extrato-expansion.tsx +172 -0
  81. package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/index.ts +1 -0
  82. package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/finance-detail-panel.tsx +241 -0
  83. package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/index.ts +2 -0
  84. package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/index.ts +2 -0
  85. package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
  86. package/dist-lib/ai/exemplos/finance/components/SacarDialog/index.ts +2 -0
  87. package/dist-lib/ai/exemplos/finance/components/SacarDialog/sacar-dialog.tsx +346 -0
  88. package/dist-lib/ai/exemplos/finance/finance-screen.tsx +821 -0
  89. package/dist-lib/ai/exemplos/finance/index.ts +1 -0
  90. package/dist-lib/ai/exemplos/gantt/_gantt-data.tsx +402 -0
  91. package/dist-lib/ai/exemplos/gantt/gantt-screen.tsx +512 -0
  92. package/dist-lib/ai/exemplos/gantt/index.ts +1 -0
  93. package/dist-lib/ai/exemplos/login/index.ts +1 -0
  94. package/dist-lib/ai/exemplos/login/login-screen.tsx +246 -0
  95. package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/consultor-detail-panel.tsx +158 -0
  96. package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/index.ts +2 -0
  97. package/dist-lib/ai/exemplos/mapa-rede/index.ts +1 -0
  98. package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede-mocks.ts +655 -0
  99. package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede.types.ts +53 -0
  100. package/dist-lib/ai/exemplos/mapa-rede/mapa-rede-screen.tsx +227 -0
  101. package/dist-lib/ai/exemplos/order-detail/components/ActivityTab.tsx +77 -0
  102. package/dist-lib/ai/exemplos/order-detail/components/AttachmentsTab.tsx +45 -0
  103. package/dist-lib/ai/exemplos/order-detail/components/CommentsTab.tsx +111 -0
  104. package/dist-lib/ai/exemplos/order-detail/components/DetailsTab.tsx +189 -0
  105. package/dist-lib/ai/exemplos/order-detail/components/OverviewTab.tsx +200 -0
  106. package/dist-lib/ai/exemplos/order-detail/components/section-card.tsx +85 -0
  107. package/dist-lib/ai/exemplos/order-detail/index.ts +1 -0
  108. package/dist-lib/ai/exemplos/order-detail/order-detail-screen.tsx +119 -0
  109. package/dist-lib/ai/exemplos/order-detail/order-mocks.ts +186 -0
  110. package/dist-lib/ai/exemplos/order-detail/order.types.ts +118 -0
  111. package/dist-lib/ai/indice.json +30 -15
  112. package/dist-lib/ai/manifest.json +31 -5
  113. package/dist-lib/ai/roteiros/app-builder/roteiro.md +155 -0
  114. package/dist-lib/ai/roteiros/auth-builder/roteiro.md +42 -0
  115. package/dist-lib/ai/roteiros/cards/roteiro.md +34 -0
  116. package/dist-lib/ai/roteiros/charts/roteiro.md +32 -0
  117. package/dist-lib/ai/roteiros/chat/roteiro.md +31 -0
  118. package/dist-lib/ai/roteiros/crud-builder/blueprint.md +63 -0
  119. package/dist-lib/ai/roteiros/crud-builder/entrevista.md +139 -0
  120. package/dist-lib/ai/roteiros/crud-builder/geracao.md +113 -0
  121. package/dist-lib/ai/roteiros/crud-builder/roteiro.md +89 -0
  122. package/dist-lib/ai/roteiros/drawers/roteiro.md +41 -0
  123. package/dist-lib/ai/roteiros/list-builder/blueprint.md +94 -0
  124. package/dist-lib/ai/roteiros/list-builder/entrevista.md +188 -0
  125. package/dist-lib/ai/roteiros/list-builder/geracao.md +63 -0
  126. package/dist-lib/ai/roteiros/list-builder/roteiro.md +91 -0
  127. package/dist-lib/ai/roteiros/module-replicator/roteiro.md +56 -0
  128. package/dist-lib/ai/roteiros/page-detail/roteiro.md +32 -0
  129. package/dist-lib/ai/roteiros/page-edit/roteiro.md +31 -0
  130. package/dist-lib/ai/roteiros/screen-composer/roteiro.md +95 -0
  131. package/package.json +1 -1
  132. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/blueprint.md +0 -0
  133. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/entrevista.md +0 -0
  134. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/geracao.md +0 -0
  135. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/roteiro.md +0 -0
@@ -0,0 +1,346 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import { Banknote, Check, Wallet } from "lucide-react";
3
+ import { Modal } from "@/components/ui/Modal";
4
+ import {
5
+ FormField,
6
+ FormFieldInput,
7
+ FormFieldSelect,
8
+ } from "@/components/ui/FormField";
9
+ import { CardCheckbox } from "@/components/ui/CardCheckbox";
10
+ import { Avatar } from "@/components/ui/avatar-ig";
11
+ import { Chip } from "@/components/ui/Chip";
12
+ import {
13
+ Tabs,
14
+ TabsList,
15
+ TabsTrigger,
16
+ TabsContent,
17
+ } from "@/components/shadcn/tabs";
18
+ import {
19
+ BANKS,
20
+ SACAR_ACCOUNT_OPTIONS,
21
+ formatBRL,
22
+ } from "../../clientes-financeiro-mocks";
23
+ import type {
24
+ BankAccount,
25
+ BankId,
26
+ FinanceClientRow,
27
+ } from "../../clientes-financeiro.types";
28
+
29
+ export type SacarDialogProps = {
30
+ open: boolean;
31
+ onOpenChange: (open: boolean) => void;
32
+ /** Cliente origem do saque (define o limite via availableBalance). */
33
+ client: FinanceClientRow | null;
34
+ /** Disparado ao confirmar — mocado, só feedback visual. */
35
+ onConfirm?: (data: {
36
+ clientId: string;
37
+ amount: number;
38
+ account: BankAccount;
39
+ }) => void;
40
+ };
41
+
42
+ /**
43
+ * SacarDialog — modal financeiro pra ação "Sacar" da action column da tabela.
44
+ *
45
+ * Layout (top → bottom):
46
+ * 1. Saldo disponível do cliente (highlight visual)
47
+ * 2. Input "Valor do saque" (BRL) + helper com limite
48
+ * 3. Cards de conta de destino (radio cards com banco + agência + conta)
49
+ * 4. Footer: Cancelar + Confirmar saque (disabled se valor inválido)
50
+ *
51
+ * Tudo mocado — `onConfirm` apenas dispara feedback no console.
52
+ * Validation visual:
53
+ * - amount > 0
54
+ * - amount <= availableBalance (caso contrário, helper red)
55
+ * - alguma conta selecionada
56
+ */
57
+ /** Aba ativa no seletor de "Conta de destino". */
58
+ type AccountTab = "cadastradas" | "outra";
59
+
60
+ /** Form da aba "Outra conta" — cadastro de nova conta bancária. */
61
+ type NewAccountForm = {
62
+ bank: BankId | "";
63
+ agency: string;
64
+ account: string;
65
+ saveForLater: boolean;
66
+ };
67
+
68
+ const EMPTY_NEW_ACCOUNT: NewAccountForm = {
69
+ bank: "",
70
+ agency: "",
71
+ account: "",
72
+ saveForLater: true,
73
+ };
74
+
75
+ const BANK_SELECT_OPTIONS = (Object.keys(BANKS) as BankId[]).map((id) => ({
76
+ value: id,
77
+ label: BANKS[id].name,
78
+ }));
79
+
80
+ export function SacarDialog({
81
+ open,
82
+ onOpenChange,
83
+ client,
84
+ onConfirm,
85
+ }: SacarDialogProps) {
86
+ const [amountStr, setAmountStr] = useState("");
87
+ const [selectedBank, setSelectedBank] = useState<BankId | null>(null);
88
+ const [activeTab, setActiveTab] = useState<AccountTab>("cadastradas");
89
+ const [newAccount, setNewAccount] =
90
+ useState<NewAccountForm>(EMPTY_NEW_ACCOUNT);
91
+
92
+ // Reset ao abrir
93
+ useEffect(() => {
94
+ if (open) {
95
+ setAmountStr("");
96
+ setSelectedBank(SACAR_ACCOUNT_OPTIONS[0]?.bank ?? null);
97
+ setActiveTab("cadastradas");
98
+ setNewAccount(EMPTY_NEW_ACCOUNT);
99
+ }
100
+ }, [open]);
101
+
102
+ const limit = client?.availableBalance ?? 0;
103
+ const amount = useMemo(() => {
104
+ const parsed = Number(amountStr.replace(",", "."));
105
+ return Number.isFinite(parsed) ? parsed : 0;
106
+ }, [amountStr]);
107
+
108
+ const overLimit = amount > limit;
109
+
110
+ // Form da nova conta: válido quando bank + agency + account preenchidos
111
+ const newAccountValid = !!(
112
+ newAccount.bank &&
113
+ newAccount.agency.trim() &&
114
+ newAccount.account.trim()
115
+ );
116
+
117
+ // canSubmit depende da aba ativa
118
+ const canSubmit =
119
+ !!client &&
120
+ amount > 0 &&
121
+ !overLimit &&
122
+ (activeTab === "cadastradas" ? !!selectedBank : newAccountValid);
123
+
124
+ const handleConfirm = () => {
125
+ if (!canSubmit || !client) return;
126
+
127
+ let account: BankAccount | undefined;
128
+ if (activeTab === "cadastradas" && selectedBank) {
129
+ account = SACAR_ACCOUNT_OPTIONS.find((a) => a.bank === selectedBank);
130
+ } else if (activeTab === "outra" && newAccountValid && newAccount.bank) {
131
+ account = {
132
+ bank: newAccount.bank,
133
+ bankName: BANKS[newAccount.bank].name,
134
+ agency: newAccount.agency.trim(),
135
+ account: newAccount.account.trim(),
136
+ };
137
+ }
138
+ if (!account) return;
139
+
140
+ onConfirm?.({
141
+ clientId: client.id,
142
+ amount,
143
+ account,
144
+ });
145
+ onOpenChange(false);
146
+ };
147
+
148
+ return (
149
+ <Modal
150
+ open={open}
151
+ onClose={() => onOpenChange(false)}
152
+ size="md"
153
+ icon={<Banknote className="size-icon-md" strokeWidth={1.7} />}
154
+ title="Realizar saque"
155
+ description={
156
+ client
157
+ ? `Saque do cliente ${client.name} (${client.id})`
158
+ : "Selecione um cliente"
159
+ }
160
+ secondaryAction={{
161
+ label: "Cancelar",
162
+ onClick: () => onOpenChange(false),
163
+ }}
164
+ primaryAction={{
165
+ label: "Confirmar saque",
166
+ onClick: handleConfirm,
167
+ disabled: !canSubmit,
168
+ }}
169
+ >
170
+ <div className="flex flex-col gap-gp-2xl">
171
+ {/* Saldo disponível — highlight financeiro
172
+ * - Label `text-fg-strong` (preto light / branco dark, sem fade).
173
+ * - Gap label↔valor = 4px (gp-xs) pra dar respiro.
174
+ * - Valor agora text-body-xl (18px, +2px do anterior body-lg=16px). */}
175
+ <div className="flex items-center justify-between p-pad-2xl rounded-radius-lg bg-bg-brand-subtle border border-border-brand">
176
+ <div className="flex items-center gap-gp-xl">
177
+ <div className="size-form-md rounded-radius-md bg-bg-brand text-white grid place-items-center">
178
+ <Wallet className="size-icon-sm" />
179
+ </div>
180
+ <div className="flex flex-col gap-gp-xs">
181
+ <span className="text-caption-md font-semibold text-fg-strong">
182
+ Saldo disponível pra saque
183
+ </span>
184
+ <span className="text-body-xl font-bold text-fg-brand tabular-nums leading-none">
185
+ {formatBRL(limit)}
186
+ </span>
187
+ </div>
188
+ </div>
189
+ </div>
190
+
191
+ {/* Valor do saque */}
192
+ <FormFieldInput
193
+ label="Valor do saque"
194
+ required
195
+ type="number"
196
+ placeholder="0,00"
197
+ value={amountStr}
198
+ onChange={(e) => setAmountStr(e.target.value)}
199
+ state={overLimit ? "error" : "default"}
200
+ helperText={
201
+ overLimit
202
+ ? `Valor acima do limite (${formatBRL(limit)})`
203
+ : `Limite: ${formatBRL(limit)}`
204
+ }
205
+ errorMessage={
206
+ overLimit
207
+ ? `Valor acima do limite (${formatBRL(limit)})`
208
+ : undefined
209
+ }
210
+ />
211
+
212
+ {/* Conta de destino — Tabs separando contas cadastradas vs nova.
213
+ * FormField com children render-prop (L-023) — widget custom (Tabs)
214
+ * herda o label padrão do DS sem replicar classes na unha. */}
215
+ <FormField label="Conta de destino">
216
+ {() => (
217
+ <Tabs fullWidth
218
+ value={activeTab}
219
+ onValueChange={(v) => setActiveTab(v as AccountTab)}
220
+ className="w-full"
221
+ >
222
+ <TabsList>
223
+ <TabsTrigger value="cadastradas">
224
+ Contas cadastradas
225
+ </TabsTrigger>
226
+ <TabsTrigger value="outra">
227
+ Outra conta
228
+ </TabsTrigger>
229
+ </TabsList>
230
+
231
+ {/* Tab 1: lista de contas existentes (radio cards) */}
232
+ <TabsContent value="cadastradas" className="mt-pad-lg">
233
+ <div className="grid grid-cols-1 gap-gp-md">
234
+ {SACAR_ACCOUNT_OPTIONS.map((acc, idx) => {
235
+ const isSelected = selectedBank === acc.bank;
236
+ const isRecommended = idx === 0;
237
+ const bankMeta = BANKS[acc.bank];
238
+ return (
239
+ <button
240
+ key={acc.bank}
241
+ type="button"
242
+ onClick={() => setSelectedBank(acc.bank)}
243
+ className={[
244
+ "flex items-center gap-gp-lg p-pad-xl rounded-radius-lg",
245
+ "border text-left",
246
+ "transition-[border-color,background-color,box-shadow] duration-150",
247
+ "focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand",
248
+ // Selected: bg verde fraco (success-muted) + border-brand
249
+ // (padrão igual ao card do Saldo disponível) — antes
250
+ // border-success deixava a borda branca no dark mode.
251
+ isSelected
252
+ ? "border-border-brand bg-bg-success-muted shadow-sh-sm"
253
+ : "border-border-default bg-bg-surface hover:border-border-input hover:bg-bg-muted",
254
+ ].join(" ")}
255
+ >
256
+ <Avatar
257
+ size="lg"
258
+ colorHex={bankMeta.color}
259
+ className="text-body-sm font-bold"
260
+ >
261
+ {bankMeta.initials}
262
+ </Avatar>
263
+ <div className="flex flex-col flex-1 min-w-0 gap-gp-2xs">
264
+ <div className="flex items-center gap-gp-sm">
265
+ <span className="text-body-sm font-semibold text-fg-default truncate">
266
+ {acc.bankName}
267
+ </span>
268
+ {isRecommended && (
269
+ <Chip
270
+ color="success"
271
+ variant="soft"
272
+ size="sm"
273
+ shape="rounded"
274
+ >
275
+ Recomendado
276
+ </Chip>
277
+ )}
278
+ </div>
279
+ <span className="text-caption-md text-fg-muted tabular-nums">
280
+ Ag {acc.agency} · Conta {acc.account}
281
+ </span>
282
+ </div>
283
+ {isSelected && (
284
+ <Check className="size-icon-sm text-fg-success shrink-0" />
285
+ )}
286
+ </button>
287
+ );
288
+ })}
289
+ </div>
290
+ </TabsContent>
291
+
292
+ {/* Tab 2: outra conta — formulário pra cadastrar nova conta.
293
+ * Campos: banco (select), agência, conta + CardCheckbox "salvar".
294
+ * `gap-form-gap` (20px) = token DS pra spacing entre fields. */}
295
+ <TabsContent value="outra" className="mt-pad-lg">
296
+ <div className="flex flex-col gap-form-gap">
297
+ <FormFieldSelect
298
+ label="Banco"
299
+ required
300
+ placeholder="Selecione o banco"
301
+ options={BANK_SELECT_OPTIONS}
302
+ value={newAccount.bank || undefined}
303
+ onValueChange={(v) =>
304
+ setNewAccount((s) => ({ ...s, bank: v as BankId }))
305
+ }
306
+ />
307
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-form-gap">
308
+ <FormFieldInput
309
+ label="Agência"
310
+ required
311
+ placeholder="0000"
312
+ value={newAccount.agency}
313
+ onChange={(e) =>
314
+ setNewAccount((s) => ({ ...s, agency: e.target.value }))
315
+ }
316
+ />
317
+ <FormFieldInput
318
+ label="Conta"
319
+ required
320
+ placeholder="00000-0"
321
+ value={newAccount.account}
322
+ onChange={(e) =>
323
+ setNewAccount((s) => ({
324
+ ...s,
325
+ account: e.target.value,
326
+ }))
327
+ }
328
+ />
329
+ </div>
330
+ <CardCheckbox
331
+ label="Salvar essa conta pra usar depois"
332
+ description="A conta aparecerá nas próximas vezes em 'Contas cadastradas'."
333
+ checked={newAccount.saveForLater}
334
+ onCheckedChange={(v) =>
335
+ setNewAccount((s) => ({ ...s, saveForLater: v === true }))
336
+ }
337
+ />
338
+ </div>
339
+ </TabsContent>
340
+ </Tabs>
341
+ )}
342
+ </FormField>
343
+ </div>
344
+ </Modal>
345
+ );
346
+ }