diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..acec653 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Build +bin/ +obj/ + +# Visual Studio +.vs/ +*.user +*.suo + +# Rider / VSCode (opcional) +.idea/ +.vscode/ + +# Logs +*.log + +# Arquivos temporários +*.tmp + +# Windows +Thumbs.db \ No newline at end of file diff --git a/App.xaml b/App.xaml new file mode 100644 index 0000000..db385e4 --- /dev/null +++ b/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/App.xaml.cs b/App.xaml.cs new file mode 100644 index 0000000..834142d --- /dev/null +++ b/App.xaml.cs @@ -0,0 +1,14 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace UI +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } + +} diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs new file mode 100644 index 0000000..b0ec827 --- /dev/null +++ b/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Assets/Images/Logo_simples.png b/Assets/Images/Logo_simples.png new file mode 100644 index 0000000..25058e1 Binary files /dev/null and b/Assets/Images/Logo_simples.png differ diff --git a/Assets/Images/avatar_user.png b/Assets/Images/avatar_user.png new file mode 100644 index 0000000..d901aed Binary files /dev/null and b/Assets/Images/avatar_user.png differ diff --git a/Assets/Images/background_preview.png b/Assets/Images/background_preview.png new file mode 100644 index 0000000..4f160d0 Binary files /dev/null and b/Assets/Images/background_preview.png differ diff --git a/Assets/Images/background_texture.png b/Assets/Images/background_texture.png new file mode 100644 index 0000000..e096729 Binary files /dev/null and b/Assets/Images/background_texture.png differ diff --git a/Assets/Images/icon_email.png b/Assets/Images/icon_email.png new file mode 100644 index 0000000..9f531de Binary files /dev/null and b/Assets/Images/icon_email.png differ diff --git a/Assets/Images/icon_eye.png b/Assets/Images/icon_eye.png new file mode 100644 index 0000000..7273075 Binary files /dev/null and b/Assets/Images/icon_eye.png differ diff --git a/Assets/Images/icon_password.png b/Assets/Images/icon_password.png new file mode 100644 index 0000000..6f6913a Binary files /dev/null and b/Assets/Images/icon_password.png differ diff --git a/Assets/Images/logo_levelcode.png b/Assets/Images/logo_levelcode.png new file mode 100644 index 0000000..e90148c Binary files /dev/null and b/Assets/Images/logo_levelcode.png differ diff --git a/Assets/Images/logo_levelcode.svg b/Assets/Images/logo_levelcode.svg new file mode 100644 index 0000000..2ec03ac --- /dev/null +++ b/Assets/Images/logo_levelcode.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LevelcodeSGI + + + + SISTEMA DE GESTÃO INTEGRADO + + + + + + diff --git a/Assets/Images/logo_levelcode2.png b/Assets/Images/logo_levelcode2.png new file mode 100644 index 0000000..34c8515 Binary files /dev/null and b/Assets/Images/logo_levelcode2.png differ diff --git a/Cadastro/FrmCadastroClientes.xaml b/Cadastro/FrmCadastroClientes.xaml new file mode 100644 index 0000000..1c9c77c --- /dev/null +++ b/Cadastro/FrmCadastroClientes.xaml @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Cadastro/FrmCadastroClientes.xaml.cs b/Cadastro/FrmCadastroClientes.xaml.cs new file mode 100644 index 0000000..652637a --- /dev/null +++ b/Cadastro/FrmCadastroClientes.xaml.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace UI.Cadastro +{ + /// + /// Lógica interna para FrmCadastroClientes.xaml + /// + public partial class FrmCadastroClientes : Window + { + public FrmCadastroClientes() + { + InitializeComponent(); + } + + private void BtnSair_Click(object sender, RoutedEventArgs e) + { + this.Close(); + } + } +} diff --git a/Configuracao/ConfiguracaoBanco.xaml b/Configuracao/ConfiguracaoBanco.xaml new file mode 100644 index 0000000..6556a00 --- /dev/null +++ b/Configuracao/ConfiguracaoBanco.xaml @@ -0,0 +1,707 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Dashboard/DashboardMain.xaml.cs b/Dashboard/DashboardMain.xaml.cs new file mode 100644 index 0000000..61c1480 --- /dev/null +++ b/Dashboard/DashboardMain.xaml.cs @@ -0,0 +1,460 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Security.Cryptography.Xml; +using System.Windows; +using System.Windows.Input; +using UI.Database; + + +namespace UI.Dashboard +{ + // ───────────────────────────────────────── + // MODEL + // ───────────────────────────────────────── + public class PessoaViewModel + { + public int Id { get; set; } + public string NomeCompleto { get; set; } = ""; + public string Email { get; set; } = ""; + public string Telefone { get; set; } = ""; + public string Cidade { get; set; } = ""; + public string Cargo { get; set; } = ""; + public DateTime? DataNascimento { get; set; } + + public string DataNascFormatada => + DataNascimento.HasValue ? DataNascimento.Value.ToString("dd/MM/yyyy") : "-"; + + public string Iniciais + { + get + { + var p = NomeCompleto.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (p.Length >= 2) return $"{p[0][0]}{p[^1][0]}".ToUpper(); + return NomeCompleto.Length >= 2 ? NomeCompleto[..2].ToUpper() : NomeCompleto.ToUpper(); + } + } + + private static readonly (string Bg, string Fg)[] Paleta = + { + ("#1A3A6E","#60A5FA"), ("#3A1A3A","#C084FC"), ("#1A3A20","#4ADE80"), + ("#3A2A10","#FCD34D"), ("#1A2A3A","#38BDF8"), ("#3A1A20","#FB7185"), + ("#1A3A35","#34D399"), + }; + + public string AvatarBackground => Paleta[Math.Abs(Id) % Paleta.Length].Bg; + public string AvatarForeground => Paleta[Math.Abs(Id) % Paleta.Length].Fg; + } + + // ───────────────────────────────────────── + // MODEL DA PAGINACAO + // ───────────────────────────────────────── + public class PaginaItem + { + public string Label { get; set; } = ""; + public bool IsActive { get; set; } + public string FontWeight => IsActive ? "Bold" : "Normal"; + } + + // ───────────────────────────────────────── + // REPOSITORIO + // ───────────────────────────────────────── + public class PessoaRepository + { + private readonly string _connectionString; + + public PessoaRepository(string connectionString) + { + _connectionString = connectionString; + } + + public (List Itens, int TotalRegistros) Buscar( + string filtro, int pagina, int itensPorPagina) + { + using var conn = new SqlConnection(_connectionString); + conn.Open(); + + var filtroParam = string.IsNullOrWhiteSpace(filtro) ? "%" : $"%{filtro}%"; + var offset = (pagina - 1) * itensPorPagina; + + int total; + + using (var cmdCount = new SqlCommand(@" + SELECT COUNT(*) + FROM Pessoas + WHERE @filtro = '%' + OR NomeCompleto LIKE @filtro + OR Email LIKE @filtro + OR Telefone LIKE @filtro", conn)) + { + cmdCount.Parameters.AddWithValue("@filtro", filtroParam); + total = (int)cmdCount.ExecuteScalar(); + } + + var itens = new List(); + + using (var cmd = new SqlCommand(@" + SELECT Id, NomeCompleto, Email, Telefone, Cidade, Cargo, DataNascimento + FROM Pessoas + WHERE @filtro = '%' + OR NomeCompleto LIKE @filtro + OR Email LIKE @filtro + OR Cidade LIKE @filtro + OR Cargo LIKE @filtro + ORDER BY NomeCompleto + OFFSET @offset ROWS FETCH NEXT @qtd ROWS ONLY", conn)) + { + cmd.Parameters.AddWithValue("@filtro", filtroParam); + cmd.Parameters.AddWithValue("@offset", offset); + cmd.Parameters.AddWithValue("@qtd", itensPorPagina); + + using var reader = cmd.ExecuteReader(); + + while (reader.Read()) + { + itens.Add(new PessoaViewModel + { + Id = reader.GetInt32(0), + NomeCompleto = reader.IsDBNull(1) ? "" : reader.GetString(1), + Email = reader.IsDBNull(2) ? "" : reader.GetString(2), + Telefone = reader.IsDBNull(3) ? "" : reader.GetString(3), + Cidade = reader.IsDBNull(4) ? "" : reader.GetString(4), + Cargo = reader.IsDBNull(5) ? "" : reader.GetString(5), + DataNascimento = reader.IsDBNull(6) ? null : reader.GetDateTime(6) + }); + } + } + + return (itens, total); + } + } + + // ───────────────────────────────────────── + // CODE-BEHIND + // ───────────────────────────────────────── + public partial class DashboardMain : Window + { + private PessoaRepository? _repo; + private int _paginaAtual = 1; + private int _itensPorPagina = 10; + private int _totalRegistros = 0; + private string _filtroAtual = ""; + + // Controles da tabela — resolvidos via FindName no OnLoaded + private System.Windows.Controls.Border? _loadingPanel; + private System.Windows.Controls.Border? _emptyPanel; + private System.Windows.Controls.ItemsControl? _listaPessoas; + private System.Windows.Controls.ItemsControl? _paginacaoPanel; + private System.Windows.Controls.Button? _btnAnterior; + private System.Windows.Controls.Button? _btnProximo; + private System.Windows.Controls.TextBlock? _runPaginaInfo; + + // ✅ Barras do gráfico de Distribuição por Sexo + private System.Windows.Controls.Border? _barMasc; + private System.Windows.Controls.Border? _barFem; + private System.Windows.Controls.Border? _barOutros; + + // ───────────────────────────────────────── + // CONSTRUTOR + // ───────────────────────────────────────── + public DashboardMain() + { + InitializeComponent(); + Loaded += OnLoaded; + + this.lblCadHoje.Text = ObterCadastrosHoje().ToString(); + this.CarregarResumo(); + } + + // ───────────────────────────────────────── + // QUERIES — inalteradas em relação ao original + // ───────────────────────────────────────── + public int ObterCadastrosHoje() + { + using var conn = new SqlConnection(DadosConexao.ObterStringConexao()); + conn.Open(); + using var cmd = new SqlCommand( + "SELECT TotalHoje FROM vw_CadastrosHoje", conn); + var resultado = cmd.ExecuteScalar(); + return resultado != null ? Convert.ToInt32(resultado) : 0; + } + + public (string total, string crescimento) ObterResumoCadastros() + { + using var conn = new SqlConnection(DadosConexao.ObterStringConexao()); + conn.Open(); + using var cmd = new SqlCommand( + "SELECT TotalCadastros, CrescimentoPercentual FROM vw_ResumoCadastros", conn); + using var reader = cmd.ExecuteReader(); + if (reader.Read()) + { + int total = reader.GetInt32(0); + decimal crescimento = reader.GetDecimal(1); + return (total.ToString("N0"), $"↑ {Math.Round(crescimento)}%"); + } + return ("0", "0%"); + } + + public (string ativos, string inativos) ObterStatusPessoas() + { + using var conn = new SqlConnection(DadosConexao.ObterStringConexao()); + conn.Open(); + using var cmd = new SqlCommand( + "SELECT Ativos, Inativos FROM vw_StatusPessoas", conn); + using var reader = cmd.ExecuteReader(); + if (reader.Read()) + { + int ativos = reader.GetInt32(0); + int inativos = reader.GetInt32(1); + return (ativos.ToString("N0"), inativos.ToString("N0")); + } + return ("0", "0"); + } + + // ✅ Query original preservada — apenas 3 colunas, sem alterar a view + public (string masc, string fem, string outros) ObterDistribuicaoSexo() + { + using var conn = new SqlConnection(DadosConexao.ObterStringConexao()); + conn.Open(); + using var cmd = new SqlCommand( + "SELECT PercentMasculino, PercentFeminino, PercentOutros FROM vw_DistribuicaoSexo", + conn); + using var reader = cmd.ExecuteReader(); + if (reader.Read()) + { + decimal masc = reader.GetDecimal(0); + decimal fem = reader.GetDecimal(1); + decimal outros = reader.GetDecimal(2); + return ( + $"{Math.Round(masc)}%", + $"{Math.Round(fem)}%", + $"{Math.Round(outros)}%" + ); + } + return ("0%", "0%", "0%"); + } + + // ───────────────────────────────────────── + // CARREGA RESUMO (cards + gráfico) + // ───────────────────────────────────────── + private void CarregarResumo() + { + var resumo = ObterResumoCadastros(); + var status = ObterStatusPessoas(); + var sexo = ObterDistribuicaoSexo(); + + TxtTotalCadastros.Text = resumo.total; + TxtCrescimento.Text = resumo.crescimento; + TxtAtivos.Text = status.ativos; + TxtInativos.Text = status.inativos; + + // Percentuais nos TextBlocks do gráfico + TxtMasc.Text = sexo.masc; + TxtFem.Text = sexo.fem; + TxtOutros.Text = sexo.outros; + + // Tenta atualizar as barras — se Loaded ainda não rodou, + // os campos serão null e a chamada é no-op. + // O OnLoaded chama novamente para garantir. + AtualizarBarrasGrafico(sexo.masc, sexo.fem, sexo.outros); + } + + // ───────────────────────────────────────── + // GRÁFICO DE BARRAS — DISTRIBUIÇÃO POR SEXO + // ───────────────────────────────────────── + + /// + /// Recebe as strings de percentual ("52%", "43%", "5%") + /// e ajusta a largura de cada barra proporcionalmente. + /// + private void AtualizarBarrasGrafico(string mascPct, string femPct, string outrosPct) + { + const double BarMaxWidth = 250; // px — ajuste se o card mudar de tamanho + const double BarMinWidth = 4; // evita barra invisível quando valor é 0 + + double m = ParsePct(mascPct); + double f = ParsePct(femPct); + double o = ParsePct(outrosPct); + + // Normaliza caso a soma não seja exatamente 100 + double soma = m + f + o; + if (soma > 0) { m = m / soma * 100; f = f / soma * 100; o = o / soma * 100; } + + if (_barMasc != null) _barMasc.Width = Math.Max(BarMinWidth, m / 100 * BarMaxWidth); + if (_barFem != null) _barFem.Width = Math.Max(BarMinWidth, f / 100 * BarMaxWidth); + if (_barOutros != null) _barOutros.Width = Math.Max(BarMinWidth, o / 100 * BarMaxWidth); + } + + /// Converte "52%" → 52.0 com segurança. + private static double ParsePct(string pct) + { + var limpo = pct.Replace("%", "").Replace(",", ".").Trim(); + return double.TryParse(limpo, + System.Globalization.NumberStyles.Any, + System.Globalization.CultureInfo.InvariantCulture, + out double v) ? v : 0; + } + + // ───────────────────────────────────────── + // LOADED + // ───────────────────────────────────────── + private void OnLoaded(object sender, RoutedEventArgs e) + { + // Controles da tabela + _loadingPanel = FindName("LoadingPanel") as System.Windows.Controls.Border; + _emptyPanel = FindName("EmptyPanel") as System.Windows.Controls.Border; + _listaPessoas = FindName("ListaPessoas") as System.Windows.Controls.ItemsControl; + _paginacaoPanel = FindName("PaginacaoPanel") as System.Windows.Controls.ItemsControl; + _btnAnterior = FindName("BtnAnterior") as System.Windows.Controls.Button; + _btnProximo = FindName("BtnProximo") as System.Windows.Controls.Button; + _runPaginaInfo = FindName("RunPaginaInfo") as System.Windows.Controls.TextBlock; + + // ✅ Barras do gráfico + _barMasc = FindName("BarMasc") as System.Windows.Controls.Border; + _barFem = FindName("BarFem") as System.Windows.Controls.Border; + _barOutros = FindName("BarOutros") as System.Windows.Controls.Border; + + // Aplica as barras agora que os controles estão resolvidos + AtualizarBarrasGrafico(TxtMasc.Text, TxtFem.Text, TxtOutros.Text); + + // Inicializa repositório e carrega a tabela + try + { + string conexao = DadosConexao.ObterStringConexao(); + if (string.IsNullOrWhiteSpace(conexao)) + { + MessageBox.Show( + "String de conexão não configurada.\nVerifique DadosConexao.ObterStringConexao().", + "Configuração", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + _repo = new PessoaRepository(conexao); + CarregarPessoas(); + } + catch (Exception ex) + { + MessageBox.Show($"Erro ao inicializar conexão:\n{ex.Message}", + "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + // ───────────────────────────────────────── + // JANELA + // ───────────────────────────────────────── + private void Window_MouseDown(object sender, MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) DragMove(); + } + + private void BtnFechar_Click(object sender, RoutedEventArgs e) + { + Application.Current.Shutdown(); + } + + // ───────────────────────────────────────── + // TABELA / PAGINAÇÃO + // ───────────────────────────────────────── + private void CarregarPessoas() + { + if (_repo == null) return; + + if (_loadingPanel != null) _loadingPanel.Visibility = Visibility.Visible; + if (_emptyPanel != null) _emptyPanel.Visibility = Visibility.Collapsed; + if (_listaPessoas != null) _listaPessoas.ItemsSource = null; + + try + { + var (itens, total) = _repo.Buscar(_filtroAtual, _paginaAtual, _itensPorPagina); + _totalRegistros = total; + + if (itens.Count == 0) + { + if (_emptyPanel != null) _emptyPanel.Visibility = Visibility.Visible; + } + else + { + if (_listaPessoas != null) _listaPessoas.ItemsSource = itens; + } + + AtualizarPaginacao(); + AtualizarInfoRegistros(); + } + catch (Exception ex) + { + MessageBox.Show($"Erro ao carregar pessoas:\n{ex.Message}", + "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } + finally + { + if (_loadingPanel != null) _loadingPanel.Visibility = Visibility.Collapsed; + } + } + + private void AtualizarPaginacao() + { + int totalPaginas = (int)Math.Ceiling(_totalRegistros / (double)_itensPorPagina); + if (totalPaginas < 1) totalPaginas = 1; + + int inicio = Math.Max(1, _paginaAtual - 2); + int fim = Math.Min(totalPaginas, inicio + 4); + inicio = Math.Max(1, fim - 4); + + var paginas = new List(); + + if (inicio > 1) + paginas.Add(new PaginaItem { Label = "..." }); + + for (int i = inicio; i <= fim; i++) + paginas.Add(new PaginaItem { Label = i.ToString(), IsActive = i == _paginaAtual }); + + if (fim < totalPaginas) + paginas.Add(new PaginaItem { Label = "..." }); + + if (_paginacaoPanel != null) _paginacaoPanel.ItemsSource = paginas; + if (_btnAnterior != null) _btnAnterior.IsEnabled = _paginaAtual > 1; + if (_btnProximo != null) _btnProximo.IsEnabled = _paginaAtual < totalPaginas; + } + + private void AtualizarInfoRegistros() + { + if (_runPaginaInfo == null) return; + + int ini = (_paginaAtual - 1) * _itensPorPagina + 1; + int fim = Math.Min(_paginaAtual * _itensPorPagina, _totalRegistros); + + _runPaginaInfo.Text = _totalRegistros == 0 + ? "0 registros" + : $"{ini}-{fim} de {_totalRegistros:N0}"; + } + + private void BtnAnterior_Click(object sender, RoutedEventArgs e) + { + if (_paginaAtual > 1) { _paginaAtual--; CarregarPessoas(); } + } + + private void BtnProximo_Click(object sender, RoutedEventArgs e) + { + int totalPaginas = (int)Math.Ceiling(_totalRegistros / (double)_itensPorPagina); + if (_paginaAtual < totalPaginas) { _paginaAtual++; CarregarPessoas(); } + } + + private void CmbItensPorPagina_SelectionChanged(object sender, + System.Windows.Controls.SelectionChangedEventArgs e) + { + if (CmbItensPorPagina?.SelectedItem is System.Windows.Controls.ComboBoxItem item + && int.TryParse(item.Content?.ToString(), out int qtd)) + { + _itensPorPagina = qtd; + _paginaAtual = 1; + CarregarPessoas(); + } + } + + private void BtnNovoCadastro_Click(object sender, RoutedEventArgs e) + { + var cp = new UI.Cadastro.FrmCadastroClientes(); + cp.ShowDialog(); + } + } +} diff --git a/Database/DadosConexao.cs b/Database/DadosConexao.cs new file mode 100644 index 0000000..42500b8 --- /dev/null +++ b/Database/DadosConexao.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UI.Database +{ + public static class DadosConexao + { + public static string Servidor { get; set; } + public static string Banco { get; set; } + public static string Usuario { get; set; } + public static string Senha { get; set; } + public static string ObterStringConexao() + { + return $"Server={Servidor};Database={Banco};User Id={Usuario};Password={Senha};"; + } + } +} diff --git a/Database/DatabaseService.cs b/Database/DatabaseService.cs new file mode 100644 index 0000000..5806b9c --- /dev/null +++ b/Database/DatabaseService.cs @@ -0,0 +1,28 @@ +using System.Data.SqlClient; +using UI.Configuracao; + +namespace UI.Database +{ + public class DatabaseService + { + public static SqlConnection GetConnection() + { + var cfg = DatabaseConfig.Load(); + + string connectionString; + + if (cfg.Integrada) + { + connectionString = + $"Server={cfg.Servidor};Database={cfg.Banco};Trusted_Connection=True;TrustServerCertificate=True;"; + } + else + { + connectionString = + $"Server={cfg.Servidor};Database={cfg.Banco};User Id={cfg.Usuario};Password={cfg.Senha};TrustServerCertificate=True;"; + } + + return new SqlConnection(connectionString); + } + } +} \ No newline at end of file diff --git a/MainWindow.xaml b/MainWindow.xaml new file mode 100644 index 0000000..6bf5df7 --- /dev/null +++ b/MainWindow.xaml @@ -0,0 +1,898 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs new file mode 100644 index 0000000..9317a25 --- /dev/null +++ b/MainWindow.xaml.cs @@ -0,0 +1,96 @@ +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using UI.Services; + +namespace UI +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + private void Window_MouseDown(object sender, MouseButtonEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed) + { + DragMove(); + } + }//Movimentando o formulario + + private void BtnFechar_Click(object sender, RoutedEventArgs e) + { + Application.Current.Shutdown(); + }//fechar aplicativo + + private void BtnEntrar_Click(object sender, RoutedEventArgs e) + { + string email = TxtEmail.Text; + string senha = PboxSenha.Password; + + if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(senha)) + { + MessageBox.Show("Informe email e senha."); + return; + } + + bool login = AuthService.Login(email, senha); + + if (login) + { + MessageBox.Show("Login realizado com sucesso!"); + + // abrir dashboard futuramente + // new Dashboard().Show(); + // this.Close(); + } + else + { + MessageBox.Show("Usuário ou senha inválidos."); + } + } + + private void BtnMostrarSenha_Click(object sender, RoutedEventArgs e) + { + + } + + private void BtnConfiguracoes_Click(object sender, RoutedEventArgs e) + { + PopupConfiguracoes.IsOpen = !PopupConfiguracoes.IsOpen; + } + + private void MenuAparencia_Click(object sender, RoutedEventArgs e) + { + var dh = new UI.Dashboard.DashboardMain(); + dh.ShowDialog(); + } + + private void MenuConexao_Click(object sender, RoutedEventArgs e) + { + var db = new UI.Configuracao.ConfiguracaoBanco(); + db.ShowDialog(); + } + + private void MenuIdioma_Click(object sender, RoutedEventArgs e) + { + + } + + private void MenuSobre_Click(object sender, RoutedEventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/Outros/FrmAjuda.xaml b/Outros/FrmAjuda.xaml new file mode 100644 index 0000000..812bdff --- /dev/null +++ b/Outros/FrmAjuda.xaml @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Outros/FrmAjuda.xaml.cs b/Outros/FrmAjuda.xaml.cs new file mode 100644 index 0000000..2f9ed72 --- /dev/null +++ b/Outros/FrmAjuda.xaml.cs @@ -0,0 +1,24 @@ +using System.Windows; +using System.Windows.Controls; + +// ✅ Namespace deve bater exatamente com x:Class do XAML: UI.Ajuda.PaginaAjuda +// Se o seu projeto usar outro namespace raiz, ajuste aqui e no x:Class do XAML. +namespace UI.Outros +{ + public partial class FrmAjuda : UserControl + { + public FrmAjuda() + { + InitializeComponent(); + } + + private void BtnFeedback_Click(object sender, RoutedEventArgs e) + { + MessageBox.Show( + "Obrigado pelo seu feedback!\nEm breve nossa equipe entrará em contato.", + "Feedback Enviado", + MessageBoxButton.OK, + MessageBoxImage.Information); + } + } +} diff --git a/Services/AuthService.cs b/Services/AuthService.cs new file mode 100644 index 0000000..58336a6 --- /dev/null +++ b/Services/AuthService.cs @@ -0,0 +1,55 @@ +using System.Data.SqlClient; +using UI.Database; + +namespace UI.Services +{ + public class AuthService + { + public static bool Login(string email, string senha) + { + using (SqlConnection conn = DatabaseService.GetConnection()) + { + conn.Open(); + + string sql = + @"SELECT Id + FROM Usuarios + WHERE Email = @Email + AND SenhaHash = @Senha + AND Status = 1"; + + SqlCommand cmd = new SqlCommand(sql, conn); + + cmd.Parameters.AddWithValue("@Email", email); + cmd.Parameters.AddWithValue("@Senha", senha); + + object result = cmd.ExecuteScalar(); + + if (result != null) + { + int userId = (int)result; + + AtualizarUltimoLogin(conn, userId); + + return true; + } + + return false; + } + } + + private static void AtualizarUltimoLogin(SqlConnection conn, int userId) + { + string update = + @"UPDATE Usuarios + SET UltimoLogin = GETDATE() + WHERE Id = @Id"; + + SqlCommand cmd = new SqlCommand(update, conn); + + cmd.Parameters.AddWithValue("@Id", userId); + + cmd.ExecuteNonQuery(); + } + } +} \ No newline at end of file diff --git a/UI.csproj b/UI.csproj new file mode 100644 index 0000000..ffc10a4 --- /dev/null +++ b/UI.csproj @@ -0,0 +1,63 @@ + + + + WinExe + net8.0-windows + enable + enable + true + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + + + + + + + diff --git a/UI.slnx b/UI.slnx new file mode 100644 index 0000000..87e0c5f --- /dev/null +++ b/UI.slnx @@ -0,0 +1,3 @@ + + + diff --git a/background_preview.png b/background_preview.png new file mode 100644 index 0000000..4f160d0 Binary files /dev/null and b/background_preview.png differ