@snksergio/design-system 0.61.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.
- package/dist-lib/ai/blocos/chart/budget-breakdown.tsx +174 -0
- package/dist-lib/ai/blocos/indice.md +43 -0
- package/dist-lib/ai/blocos/paneldetail/detalhe-com-tabela.tsx +450 -0
- package/dist-lib/ai/blocos/paneldetail/detalhe-de-tarefa-com-abas.tsx +570 -0
- package/dist-lib/ai/blocos/paneldetail/detalhe-do-registro.tsx +555 -0
- package/dist-lib/ai/componentes/AlertModal.md +47 -0
- package/dist-lib/ai/componentes/AppShell.md +117 -0
- package/dist-lib/ai/componentes/Breadcrumb.md +187 -0
- package/dist-lib/ai/componentes/Button.md +116 -0
- package/dist-lib/ai/componentes/ButtonGroup.md +162 -0
- package/dist-lib/ai/componentes/CardCheckbox.md +99 -0
- package/dist-lib/ai/componentes/CardOption.md +133 -0
- package/dist-lib/ai/componentes/Chart.md +93 -0
- package/dist-lib/ai/componentes/Chip.md +68 -0
- package/dist-lib/ai/componentes/ChoroplethMap.md +118 -0
- package/dist-lib/ai/componentes/ColorPicker.md +70 -0
- package/dist-lib/ai/componentes/Combobox.md +51 -0
- package/dist-lib/ai/componentes/ConversationListItem.md +90 -0
- package/dist-lib/ai/componentes/DataList.md +111 -0
- package/dist-lib/ai/componentes/DataTable.md +867 -0
- package/dist-lib/ai/componentes/DatePicker.md +84 -0
- package/dist-lib/ai/componentes/DateSeparatorChip.md +59 -0
- package/dist-lib/ai/componentes/EmptyState.md +72 -0
- package/dist-lib/ai/componentes/FileUploadField.md +95 -0
- package/dist-lib/ai/componentes/FloatingPanel.md +118 -0
- package/dist-lib/ai/componentes/FooterTable.md +62 -0
- package/dist-lib/ai/componentes/FormField.md +110 -0
- package/dist-lib/ai/componentes/Gantt.md +552 -0
- package/dist-lib/ai/componentes/Header.md +98 -0
- package/dist-lib/ai/componentes/Icon.md +65 -0
- package/dist-lib/ai/componentes/Kanban.md +343 -0
- package/dist-lib/ai/componentes/Kpi.md +103 -0
- package/dist-lib/ai/componentes/List.md +61 -0
- package/dist-lib/ai/componentes/MarkdownText.md +59 -0
- package/dist-lib/ai/componentes/MenuSidebar.md +128 -0
- package/dist-lib/ai/componentes/MessageAck.md +53 -0
- package/dist-lib/ai/componentes/MessageBubble.md +115 -0
- package/dist-lib/ai/componentes/MessageComposer.md +80 -0
- package/dist-lib/ai/componentes/MessageVariablesPicker.md +104 -0
- package/dist-lib/ai/componentes/Modal.md +88 -0
- package/dist-lib/ai/componentes/MonthYearPicker.md +49 -0
- package/dist-lib/ai/componentes/PageHeader.md +129 -0
- package/dist-lib/ai/componentes/Panel.md +84 -0
- package/dist-lib/ai/componentes/Scheduler.md +421 -0
- package/dist-lib/ai/componentes/ScreenLoader.md +60 -0
- package/dist-lib/ai/componentes/SingleMenuSidebar.md +171 -0
- package/dist-lib/ai/componentes/Spinner.md +52 -0
- package/dist-lib/ai/componentes/Table.md +192 -0
- package/dist-lib/ai/componentes/TableToolbar.md +87 -0
- package/dist-lib/ai/componentes/TabsNavigation.md +152 -0
- package/dist-lib/ai/componentes/Toast.md +49 -0
- package/dist-lib/ai/componentes/_primitivos.md +74 -0
- package/dist-lib/ai/componentes/avatar-ig.md +181 -0
- package/dist-lib/ai/componentes/indice.json +49 -0
- package/dist-lib/ai/exemplos/app-shell/app-shell-example.tsx +140 -0
- package/dist-lib/ai/exemplos/app-shell/index.ts +3 -0
- package/dist-lib/ai/exemplos/app-shell/nav-data.ts +97 -0
- package/dist-lib/ai/exemplos/app-shell/routes.tsx +75 -0
- package/dist-lib/ai/exemplos/chat/chat-screen.tsx +152 -0
- package/dist-lib/ai/exemplos/chat/chat-v2-mocks.ts +171 -0
- package/dist-lib/ai/exemplos/chat/chat-v2.styles.ts +23 -0
- package/dist-lib/ai/exemplos/chat/chat-v2.types.ts +81 -0
- package/dist-lib/ai/exemplos/chat/components/ChannelDot/channel-dot.tsx +28 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/conversation-actions-menu.tsx +83 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/index.ts +4 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.styles.ts +22 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.tsx +203 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.types.ts +10 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.styles.ts +55 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.tsx +52 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.types.ts +7 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/DateSeparator/date-separator.tsx +18 -0
- package/dist-lib/ai/exemplos/chat/components/DetailField/detail-field.tsx +23 -0
- package/dist-lib/ai/exemplos/chat/components/DetailSection/detail-section.tsx +41 -0
- package/dist-lib/ai/exemplos/chat/components/DetailSection/index.ts +1 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.styles.ts +30 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.tsx +142 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.types.ts +16 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/index.ts +5 -0
- package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.styles.ts +37 -0
- package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.tsx +45 -0
- package/dist-lib/ai/exemplos/chat/components/FilterRow/index.ts +1 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.styles.ts +27 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.tsx +66 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.types.ts +13 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-rail.tsx +38 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/index.ts +6 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.styles.ts +37 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.tsx +29 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.types.ts +5 -0
- package/dist-lib/ai/exemplos/chat/components/PersonAvatar/index.ts +5 -0
- package/dist-lib/ai/exemplos/chat/components/PersonAvatar/person-avatar.tsx +31 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.styles.ts +19 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.tsx +140 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.types.ts +13 -0
- package/dist-lib/ai/exemplos/chat/components/RailItem/index.ts +1 -0
- package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.styles.ts +30 -0
- package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.tsx +42 -0
- package/dist-lib/ai/exemplos/chat/hooks/use-resizable.ts +98 -0
- package/dist-lib/ai/exemplos/chat/index.ts +1 -0
- package/dist-lib/ai/exemplos/clientes/_table-data.ts +59 -0
- package/dist-lib/ai/exemplos/clientes/clientes-screen.tsx +505 -0
- package/dist-lib/ai/exemplos/clientes/clientes-showcase-mocks.ts +117 -0
- package/dist-lib/ai/exemplos/clientes/clientes-showcase.styles.ts +13 -0
- package/dist-lib/ai/exemplos/clientes/clientes-showcase.types.ts +16 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.styles.ts +28 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.tsx +303 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.types.ts +14 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/index.ts +2 -0
- package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/index.ts +2 -0
- package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
- package/dist-lib/ai/exemplos/clientes/index.ts +1 -0
- package/dist-lib/ai/exemplos/dashboard/dashboard-brazil-map.ts +33 -0
- package/dist-lib/ai/exemplos/dashboard/dashboard-screen.tsx +1110 -0
- package/dist-lib/ai/exemplos/dashboard/index.ts +1 -0
- package/dist-lib/ai/exemplos/edit-page/components/StepNav.tsx +81 -0
- package/dist-lib/ai/exemplos/edit-page/components/section-card.tsx +85 -0
- package/dist-lib/ai/exemplos/edit-page/edit-page-screen.tsx +234 -0
- package/dist-lib/ai/exemplos/edit-page/index.ts +1 -0
- package/dist-lib/ai/exemplos/finance/_table-data.ts +57 -0
- package/dist-lib/ai/exemplos/finance/clientes-financeiro-mocks.ts +227 -0
- package/dist-lib/ai/exemplos/finance/clientes-financeiro.types.ts +75 -0
- package/dist-lib/ai/exemplos/finance/clientes-showcase-mocks.ts +117 -0
- package/dist-lib/ai/exemplos/finance/clientes-showcase.styles.ts +13 -0
- package/dist-lib/ai/exemplos/finance/clientes-showcase.types.ts +16 -0
- package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/editar-finance-drawer.tsx +241 -0
- package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/index.ts +5 -0
- package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/extrato-expansion.tsx +172 -0
- package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/index.ts +1 -0
- package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/finance-detail-panel.tsx +241 -0
- package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/index.ts +2 -0
- package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/index.ts +2 -0
- package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
- package/dist-lib/ai/exemplos/finance/components/SacarDialog/index.ts +2 -0
- package/dist-lib/ai/exemplos/finance/components/SacarDialog/sacar-dialog.tsx +346 -0
- package/dist-lib/ai/exemplos/finance/finance-screen.tsx +821 -0
- package/dist-lib/ai/exemplos/finance/index.ts +1 -0
- package/dist-lib/ai/exemplos/gantt/_gantt-data.tsx +402 -0
- package/dist-lib/ai/exemplos/gantt/gantt-screen.tsx +512 -0
- package/dist-lib/ai/exemplos/gantt/index.ts +1 -0
- package/dist-lib/ai/exemplos/login/index.ts +1 -0
- package/dist-lib/ai/exemplos/login/login-screen.tsx +246 -0
- package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/consultor-detail-panel.tsx +158 -0
- package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/index.ts +2 -0
- package/dist-lib/ai/exemplos/mapa-rede/index.ts +1 -0
- package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede-mocks.ts +655 -0
- package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede.types.ts +53 -0
- package/dist-lib/ai/exemplos/mapa-rede/mapa-rede-screen.tsx +227 -0
- package/dist-lib/ai/exemplos/order-detail/components/ActivityTab.tsx +77 -0
- package/dist-lib/ai/exemplos/order-detail/components/AttachmentsTab.tsx +45 -0
- package/dist-lib/ai/exemplos/order-detail/components/CommentsTab.tsx +111 -0
- package/dist-lib/ai/exemplos/order-detail/components/DetailsTab.tsx +189 -0
- package/dist-lib/ai/exemplos/order-detail/components/OverviewTab.tsx +200 -0
- package/dist-lib/ai/exemplos/order-detail/components/section-card.tsx +85 -0
- package/dist-lib/ai/exemplos/order-detail/index.ts +1 -0
- package/dist-lib/ai/exemplos/order-detail/order-detail-screen.tsx +119 -0
- package/dist-lib/ai/exemplos/order-detail/order-mocks.ts +186 -0
- package/dist-lib/ai/exemplos/order-detail/order.types.ts +118 -0
- package/dist-lib/ai/global/componentes.md +217 -0
- package/dist-lib/ai/global/composicao.md +182 -0
- package/dist-lib/ai/indice.json +192 -0
- package/dist-lib/ai/lint/ds-lint-patterns.mjs +115 -0
- package/dist-lib/ai/manifest.json +42 -0
- package/dist-lib/ai/regras/design.md +88 -0
- package/dist-lib/ai/regras/temas.md +192 -0
- package/dist-lib/ai/regras-por-componente.json +103 -0
- package/dist-lib/ai/roteiros/app-builder/roteiro.md +155 -0
- package/dist-lib/ai/roteiros/auth-builder/roteiro.md +42 -0
- package/dist-lib/ai/roteiros/cards/roteiro.md +34 -0
- package/dist-lib/ai/roteiros/charts/roteiro.md +32 -0
- package/dist-lib/ai/roteiros/chat/roteiro.md +31 -0
- package/dist-lib/ai/roteiros/crud-builder/blueprint.md +63 -0
- package/dist-lib/ai/roteiros/crud-builder/entrevista.md +139 -0
- package/dist-lib/ai/roteiros/crud-builder/geracao.md +113 -0
- package/dist-lib/ai/roteiros/crud-builder/roteiro.md +89 -0
- package/dist-lib/ai/roteiros/dashboard-builder/blueprint.md +47 -0
- package/dist-lib/ai/roteiros/dashboard-builder/entrevista.md +62 -0
- package/dist-lib/ai/roteiros/dashboard-builder/geracao.md +88 -0
- package/dist-lib/ai/roteiros/dashboard-builder/roteiro.md +88 -0
- package/dist-lib/ai/roteiros/drawers/roteiro.md +41 -0
- package/dist-lib/ai/roteiros/list-builder/blueprint.md +94 -0
- package/dist-lib/ai/roteiros/list-builder/entrevista.md +188 -0
- package/dist-lib/ai/roteiros/list-builder/geracao.md +63 -0
- package/dist-lib/ai/roteiros/list-builder/roteiro.md +91 -0
- package/dist-lib/ai/roteiros/module-replicator/roteiro.md +56 -0
- package/dist-lib/ai/roteiros/page-detail/roteiro.md +32 -0
- package/dist-lib/ai/roteiros/page-edit/roteiro.md +31 -0
- package/dist-lib/ai/roteiros/screen-composer/roteiro.md +95 -0
- package/package.json +4 -1
|
@@ -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
|
+
}
|