using BLL; using CustomMessageBox; using DAL; using System.Drawing; using System.Windows.Forms; namespace UI { public class ClienteCadastroPanel : UserControl { private string _connectionString = DadosDaConexao.ObterConexao(); private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); private readonly Color TextDark = Color.FromArgb(30, 41, 59); private readonly Color BorderColor = Color.FromArgb(226, 232, 240); private Panel pnlToolbar = null!; private Panel mainScroll = null!; private Panel content = null!; // Identificação private RoundTextBox txtId = null!, txtEmpresaId = null!, txtNome = null!, txtNomeFantasia = null!; private RoundTextBox txtTipoPessoa = null!, txtDocumento = null!, txtRG = null!; private RoundTextBox txtInscricaoMunicipal = null!, txtDataNascimento = null!; private RoundTextBox txtGrupo = null!, txtTipoConsumidor = null!; // Contatos private RoundTextBox txtContato = null!, txtTelefone1 = null!, txtTelefone2 = null!; private RoundTextBox txtCelular = null!, txtWhatsapp = null!, txtEmail = null!, txtEmailNFe = null!, txtSite = null!; // Endereço private RoundTextBox txtCep = null!, txtEndereco = null!, txtNumero = null!, txtComplemento = null!; private RoundTextBox txtBairro = null!, txtCidade = null!, txtUF = null!, txtPais = null!; // Financeiro private RoundTextBox txtLimiteCredito = null!, txtVendedorPadraoId = null!, txtObservacoesCobranca = null!; private CheckBox chkBloqueado = null!, chkAtivo = null!; // Carteiras private RoundTextBox txtBitcoin = null!, txtEthereum = null!, txtLitecoin = null!; // Extras private RoundTextBox txtObservacoes = null!; private RoundTextBox txtCampoExtra1 = null!, txtCampoExtra2 = null!, txtCampoExtra3 = null!; // Info (readonly) private RoundTextBox txtUltimaCompra = null!, txtCriadoEm = null!, txtAtualizadoEm = null!; //Funções Auxiliares private void CarregarConfiguracoesSistema() { BLLEmpresaConfig empresaConfig = new BLLEmpresaConfig(_connectionString); int codEmpresa = empresaConfig.ObterEmpresaAtivaId(); this.txtEmpresaId.Text = codEmpresa.ToString(); } private DateTime? ConverterData(string texto) { if (string.IsNullOrWhiteSpace(texto)) return null; if (DateTime.TryParse(texto, out DateTime data)) return data; return null; } private RoundTextBox[] TodosOsCampos() => new[] { txtId, txtEmpresaId, txtNome, txtNomeFantasia, txtTipoPessoa, txtDocumento, txtRG, txtInscricaoMunicipal, txtDataNascimento, txtGrupo, txtTipoConsumidor, txtContato, txtTelefone1, txtTelefone2, txtCelular, txtWhatsapp, txtEmail, txtEmailNFe, txtSite, txtCep, txtEndereco, txtNumero, txtComplemento, txtBairro, txtCidade, txtUF, txtPais, txtLimiteCredito, txtVendedorPadraoId, txtObservacoesCobranca, txtBitcoin, txtEthereum, txtLitecoin, txtObservacoes, txtCampoExtra1, txtCampoExtra2, txtCampoExtra3 }; private void SetCampos(bool enabled) { foreach (var campo in TodosOsCampos()) { campo.Enabled = enabled; campo.BackColor = enabled ? Color.White : Color.FromArgb(241, 245, 249); } chkBloqueado.Enabled = enabled; chkAtivo.Enabled = enabled; } public ClienteCadastroPanel() { Dock = DockStyle.Fill; BackColor = Color.White; DoubleBuffered = true; InitializeLayout(); SetCampos(false); } private void InitializeLayout() { this.Controls.Clear(); // ── TOOLBAR ─────────────────────────────────────────────────────── pnlToolbar = new Panel { Dock = DockStyle.Top, Height = 55, BackColor = Color.FromArgb(248, 250, 252), BorderStyle = BorderStyle.None }; var flowButtons = new FlowLayoutPanel { Dock = DockStyle.Fill, Padding = new Padding(12, 10, 0, 0), BackColor = Color.Transparent }; var btnNovo = CreateToolbarButton("Novo", Color.FromArgb(34, 197, 94)); var btnAlterar = CreateToolbarButton("Alterar", Color.FromArgb(245, 158, 11)); var btnExcluir = CreateToolbarButton("Excluir", Color.FromArgb(239, 68, 68)); var btnLocalizar = CreateToolbarButton("Localizar", AccentBlue); var btnSalvar = CreateToolbarButton("Salvar", AccentBlue); var btnCancelar = CreateToolbarButton("Cancelar", Color.FromArgb(148, 163, 184)); btnNovo.Click += (s, e) => BtnNovo_Click(); btnAlterar.Click += (s, e) => BtnAlterar_Click(); btnExcluir.Click += (s, e) => BtnExcluir_Click(); btnLocalizar.Click += (s, e) => BtnLocalizar_Click(); btnSalvar.Click += (s, e) => BtnSalvar_Click(); btnCancelar.Click += (s, e) => BtnCancelar_Click(); flowButtons.Controls.AddRange(new Control[] { btnNovo, btnAlterar, btnExcluir, btnLocalizar, btnSalvar, btnCancelar }); pnlToolbar.Controls.Add(flowButtons); this.Controls.Add(pnlToolbar); // ── SCROLL + CONTENT ────────────────────────────────────────────── mainScroll = new Panel { Dock = DockStyle.Fill, AutoScroll = true, BackColor = Color.White }; this.Controls.Add(mainScroll); mainScroll.BringToFront(); content = new Panel { Width = 1100, Height = 900, Location = new Point(0, 0), BackColor = Color.White }; mainScroll.Controls.Add(content); const int rowH = 52; const int secGap = 10; const int secH = 28; const int inputH = 28; int y = 10; // ── 1. IDENTIFICAÇÃO DO CLIENTE ─────────────────────────────────── content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO CLIENTE", y)); y += secH + 4; txtId = AddInput(content, "ID", 20, y, 60, inputH); txtEmpresaId = AddInput(content, "Empresa ID", 90, y, 80, inputH); txtNome = AddInput(content, "Nome / Razão Social", 180, y, 390, inputH); txtNomeFantasia = AddInput(content, "Nome Fantasia", 580, y, 360, inputH); y += rowH; txtDocumento = AddInput(content, "CPF/CNPJ", 20, y, 170, inputH); DocumentoHelper.Registrar(txtDocumento); txtRG = AddInput(content, "RG / Insc. Estadual", 200, y, 170, inputH); txtInscricaoMunicipal = AddInput(content, "Insc. Municipal", 380, y, 130, inputH); txtDataNascimento = AddInput(content, "Dt. Nascimento", 520, y, 130, inputH); txtTipoPessoa = AddInput(content, "Tipo Pessoa", 660, y, 110, inputH); txtGrupo = AddInput(content, "Grupo", 780, y, 110, inputH); txtTipoConsumidor = AddInput(content, "Tipo Consumidor", 900, y, 140, inputH); y += rowH; // ── 2. CONTATOS E COMUNICAÇÃO ───────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("CONTATOS E COMUNICAÇÃO", y)); y += secH + 4; txtContato = AddInput(content, "Contato", 20, y, 180, inputH); txtEmail = AddInput(content, "E-mail", 210, y, 230, inputH); txtEmailNFe = AddInput(content, "E-mail XML/NFe", 450, y, 230, inputH); txtSite = AddInput(content, "Site", 690, y, 250, inputH); y += rowH; txtTelefone1 = AddInput(content, "Telefone 1", 20, y, 155, inputH); txtTelefone2 = AddInput(content, "Telefone 2", 185, y, 155, inputH); txtCelular = AddInput(content, "Celular", 350, y, 155, inputH); txtWhatsapp = AddInput(content, "WhatsApp", 515, y, 155, inputH); y += rowH; // ── 3. ENDEREÇO COMPLETO ────────────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("ENDEREÇO COMPLETO", y)); y += secH + 4; txtCep = AddInput(content, "CEP", 20, y, 95, inputH); txtCep.Leave += (s, e) => { string cep = txtCep.Text.Trim().Replace("-", ""); if (cep.Length != 8) return; if (TLL.VerifyCep.verificaCEP(cep)) { txtEndereco.Text = TLL.VerifyCep.endereco; txtBairro.Text = TLL.VerifyCep.bairro; txtCidade.Text = TLL.VerifyCep.cidade; txtUF.Text = TLL.VerifyCep.estado; // Formata o CEP com hífen txtCep.Text = $"{cep[..5]}-{cep[5..]}"; } else { NT_MessageBox.Show("CEP não encontrado.", "CEP", MessageBoxButtons.OK, MessageBoxIcon.Warning); } };//cep txtEndereco = AddInput(content, "Logradouro", 125, y, 370, inputH); txtNumero = AddInput(content, "Nº", 505, y, 60, inputH); txtComplemento = AddInput(content, "Complemento", 575, y, 175, inputH); txtBairro = AddInput(content, "Bairro", 760, y, 180, inputH); y += rowH; txtCidade = AddInput(content, "Cidade", 20, y, 280, inputH); txtUF = AddInput(content, "UF", 310, y, 55, inputH); txtPais = AddInput(content, "País", 375, y, 150, inputH); y += rowH; // ── 4. FINANCEIRO ───────────────────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("FINANCEIRO", y)); y += secH + 4; txtLimiteCredito = AddInput(content, "Limite de Crédito", 20, y, 150, inputH); txtVendedorPadraoId = AddInput(content, "Vendedor Padrão ID", 180, y, 120, inputH); txtObservacoesCobranca = AddInput(content, "Obs. de Cobrança", 310, y, 380, inputH); chkBloqueado = CreateCheckBox("Bloqueado", 705, y + 18); chkAtivo = CreateCheckBox("Ativo", 805, y + 18); content.Controls.Add(chkBloqueado); content.Controls.Add(chkAtivo); y += rowH; // ── 5. CARTEIRAS DIGITAIS ───────────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("CARTEIRAS DIGITAIS", y)); y += secH + 4; txtBitcoin = AddInput(content, "Bitcoin (BTC)", 20, y, 290, inputH); txtEthereum = AddInput(content, "Ethereum (ETH)", 320, y, 290, inputH); txtLitecoin = AddInput(content, "Litecoin (LTC)", 620, y, 290, inputH); y += rowH; // ── 6. CAMPOS EXTRAS ────────────────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("CAMPOS EXTRAS", y)); y += secH + 4; txtCampoExtra1 = AddInput(content, "Campo Extra 1", 20, y, 290, inputH); txtCampoExtra2 = AddInput(content, "Campo Extra 2", 320, y, 290, inputH); txtCampoExtra3 = AddInput(content, "Campo Extra 3", 620, y, 290, inputH); y += rowH; // ── 7. OBSERVAÇÕES ──────────────────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("OBSERVAÇÕES", y)); y += secH + 4; txtObservacoes = AddInput(content, "Observações Internas", 20, y, 920, inputH); y += rowH; // ── 8. INFORMAÇÕES DO REGISTRO ──────────────────────────────────── y += secGap; content.Controls.Add(CreateSectionHeader("INFORMAÇÕES DO REGISTRO", y)); y += secH + 4; txtUltimaCompra = AddInput(content, "Última Compra", 20, y, 175, inputH, readOnly: true); txtCriadoEm = AddInput(content, "Criado Em", 205, y, 175, inputH, readOnly: true); txtAtualizadoEm = AddInput(content, "Atualizado Em", 390, y, 175, inputH, readOnly: true); y += rowH; content.Height = y + 10; } // ── EVENTOS ─────────────────────────────────────────────────────────── private void BtnNovo_Click() { foreach (var campo in TodosOsCampos()) campo.Text = string.Empty; chkBloqueado.Checked = false; chkAtivo.Checked = true; SetCampos(true); txtId.Enabled = false; txtId.BackColor = Color.FromArgb(241, 245, 249); this.CarregarConfiguracoesSistema(); txtEmpresaId.Enabled = false; txtEmpresaId.BackColor = Color.FromArgb(241, 245, 249); } private void BtnAlterar_Click() { if (string.IsNullOrWhiteSpace(txtId.Text)) { MessageBox.Show( "Nenhum registro selecionado para alterar.", "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } SetCampos(true); txtId.Enabled = false; txtId.BackColor = Color.FromArgb(241, 245, 249); txtEmpresaId.Enabled = false; txtEmpresaId.BackColor = Color.FromArgb(241, 245, 249); } private void BtnExcluir_Click() { // Solicita confirmação e exclui o registro atual } private void BtnLocalizar_Click() { // Abre tela/diálogo de busca e preenche os campos } private void BtnSalvar_Click() { var bll = new BLLClientes(_connectionString); // 🔒 validação básica front if (string.IsNullOrWhiteSpace(txtNome.Text) || string.IsNullOrWhiteSpace(txtDocumento.Text)) { NT_MessageBox.Show("Preencha ao menos Nome e Documento.", "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } bool isNew = string.IsNullOrWhiteSpace(txtId.Text); var cliente = new ModeloCliente { Id = isNew ? 0 : int.Parse(txtId.Text), EmpresaId = int.TryParse(txtEmpresaId.Text, out var emp) ? emp : 0, Nome = txtNome.Text, NomeFantasia = txtNomeFantasia.Text, TipoPessoa = txtTipoPessoa.Text, Documento = txtDocumento.Text, RG = txtRG.Text, InscricaoMunicipal = txtInscricaoMunicipal.Text, DataNascimento = ConverterData(txtDataNascimento.Text), Contato = txtContato.Text, Telefone1 = txtTelefone1.Text, Telefone2 = txtTelefone2.Text, Celular = txtCelular.Text, Whatsapp = txtWhatsapp.Text, Email = txtEmail.Text, EmailNFe = txtEmailNFe.Text, Site = txtSite.Text, Grupo = txtGrupo.Text, Cep = txtCep.Text, Endereco = txtEndereco.Text, Numero = int.TryParse(txtNumero.Text, out var num) ? num : null, Complemento = txtComplemento.Text, Bairro = txtBairro.Text, Cidade = txtCidade.Text, UF = txtUF.Text, Pais = txtPais.Text, LimiteCredito = decimal.TryParse(txtLimiteCredito.Text, out var lim) ? lim : 0, Bloqueado = chkBloqueado.Checked, ObservacoesCobranca = txtObservacoesCobranca.Text, VendedorPadraoId = int.TryParse(txtVendedorPadraoId.Text, out var vend) ? vend : null, TipoConsumidor = txtTipoConsumidor.Text, Observacoes = txtObservacoes.Text, CampoExtra1 = txtCampoExtra1.Text, CampoExtra2 = txtCampoExtra2.Text, CampoExtra3 = txtCampoExtra3.Text, Bitcoin = txtBitcoin.Text, Ethereum = txtEthereum.Text, Litecoin = txtLitecoin.Text, Ativo = chkAtivo.Checked, UltimaCompra = ConverterData(txtUltimaCompra.Text), // 🔥 esses o banco já gera, mas mantém compatível CriadoEm = DateTime.Now, AtualizadoEm = DateTime.Now }; bool sucesso = false; try { sucesso = isNew ? bll.Inserir(cliente) : bll.Alterar(cliente); } catch (Exception ex) { NT_MessageBox.Show(ex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (!sucesso) { NT_MessageBox.Show("Erro ao salvar cliente.", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } SetCampos(false); NT_MessageBox.Show("Cliente salvo com sucesso!", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void BtnCancelar_Click() { foreach (var campo in TodosOsCampos()) campo.Text = string.Empty; chkBloqueado.Checked = false; chkAtivo.Checked = false; SetCampos(false); } // ── HELPERS ─────────────────────────────────────────────────────────── private Panel CreateSectionHeader(string title, int y) { var pnl = new Panel { Location = new Point(20, y), Width = 1000, Height = 26 }; var lbl = new Label { Text = title, Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), ForeColor = AccentBlue, AutoSize = true, Location = new Point(0, 0) }; var line = new Panel { BackColor = BorderColor, Height = 1, Width = 980, Location = new Point(0, 20) }; pnl.Controls.Add(lbl); pnl.Controls.Add(line); return pnl; } private RoundTextBox AddInput(Control parent, string label, int x, int y, int width, int height, bool readOnly = false) { var lbl = new Label { Text = label, Location = new Point(x, y), Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), ForeColor = readOnly ? Color.Gray : TextDark, AutoSize = true }; var txt = new RoundTextBox { Location = new Point(x, y + 16), Size = new Size(width, height), Radius = 4, BorderColor = readOnly ? Color.FromArgb(203, 213, 225) : BorderColor, FocusColor = AccentBlue, ReadOnly = readOnly, BackColor = readOnly ? Color.FromArgb(241, 245, 249) : Color.White }; parent.Controls.Add(lbl); parent.Controls.Add(txt); return txt; } private CheckBox CreateCheckBox(string text, int x, int y) => new CheckBox { Text = text, Location = new Point(x, y), Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), ForeColor = TextDark, AutoSize = true }; private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton { Text = text, Size = new Size(95, 32), BackColor = color, ForeColor = Color.White, Font = new Font("Segoe UI Semibold", 8.5f), Margin = new Padding(0, 0, 6, 0), Cursor = Cursors.Hand }; } }