Blazor - Aplicativo Despesas Pessoais com Gráfico de Barras e Pizza - I


Neste artigo vamos iniciar a criação de uma aplicação Blazor Web Assemply para gerenciar despesas pessoais onde vamos criar gráficos de barras e de pizza.

Se você esta chegando agora e não sabe o que é o Blazor leia o artigo ASP .NET Core - Iniciando com o Blazor - Macoratti; se você já conhece e quer saber mais pode fazer o meu curso de Blazor Essencial.  

Nosso objetivo será criar uma pequena aplicação para gerenciar despesas e receitas pessoais bem simples mostrando como usar os principais recursos do Blazor em um projeto Blazor Web Assembly.

Assim iremos criar formulário e realizar validações , criar componentes , criar controladores e usar o padrão repositório, usar diálogos modais , tratar com imagens e arquivos CSS e criar um dashboard com gráficos de barras e pizzas usando a biblioteca Blazor.Radzen.

Iremos criar o aplicação de uma forma objetiva e prática sem muito rigor com a arquitetura usada pois trata-se de uma estudo de caso e de um projeto exemplo a partir do qual você poderá se basear melhorando-o em diversos aspectos.

Criando um projeto Blazor Web Assembly

Abra o VS 2019 Community e selecione a opção Create a New Project;

A seguir selecione a opção Blazor WebAssembly App e clique em next;

Informe o nome da solução Financas e no projeto informe Financas.Pessoais e clique em Next;

Defina as configurações conforme mostrado na figura abaixo e clique em Create;

Note que marcamos a opção para criar o projeto usando a hospedagem ASP .NET Core.

A final teremos a solução e o projeto criados em uma arquitetura monolítica de projeto único com a seguinte estrutura exibida na janela Solution Explorer:

Definindo as entidades para Receita e Despesa e Categorias

No projeto Financas.Pessoais.Shared vamos criar as classes Receita, Despesa onde vamos definir o modelo de domínio da aplicação e as enumerações CategoriaDespesa e CategoriaReceita que representam as categorias das receitas e despesas.

1- Receita

using System;

namespace Financas.Pessoais.Shared
{
    public class Receita
    {
        public Receita()
        {
            Id = Guid.NewGuid();
        }
        public Guid Id { get; set; }
        public DateTime Data { get; set; }
        public string Descricao { get; set; }
        public CategoriaReceita Categoria { get; set; }
        public decimal Valor { get; set; }
    }
}

2- Despesa
using System;

namespace Financas.Pessoais.Shared
{
    public class Despesa
    {
        public Despesa()
        {
            Id = Guid.NewGuid();
        }
        public Guid Id { get; set; }
        public DateTime Data { get; set; }
        public string Descricao { get; set; }
        public CategoriaDespesa Categoria { get; set; }
        public decimal Valor { get; set; }
    }
}

3- CategoriaReceita
namespace Financas.Pessoais.Shared
{
    public enum CategoriaReceita
    {
        Salário,
        Lucros,
        Vendas,
        Brindes,
        Doações
    }
}

4- CategoriaDespesa

namespace Financas.Pessoais.Shared
{
    public enum CategoriaDespesa
    {
        Alimentação,
        Transporte,
        Vestuário,
        Saúde,
        Segurança,
        Educação,
        Poupança,
        Dentista,
        Entretenimento,
        Viagens,
        Pessoal,
        Extras
    }
}

Poderíamos usar outra abordagem criando apenas uma classe para representar o modelo de domínio e outra para representar as categorias pois nesta abordagem estamos duplicando código mas pela simplicidade vamos seguir esta abordagem.

Isto é tudo que precisamos fazer no projeto Shared.

Criando as opções do menu

Vamos trabalhar agora com o projeto Client.

Na pasta Shared abra o arquivo NavMenu.razor e altere o código incluindo as novas opções do menu :

...
<div class="@NavMenuCssClass nav-menu" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="receitas">
                <span class="oi oi-briefcase" aria-hidden="true"></span> Receitas
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="despesas">
                <span class="oi oi-dollar" aria-hidden="true"></span> Despesas
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="dashboard">
                <span class="oi oi-dollar" aria-hidden="true"></span> Dashboard
            </NavLink>
        </li>
    </ul>
</div>
...

Abaixo temos o resultado dos novos menus criados sendo exibidos no projeto:

Definindo a página de apresentação

Vamos incluir no componente Index.razor uma imagem para servir como página de apresentação quando a aplicação for iniciada. Para isso vamos incluir o código abaixo:

@page "/"
<img src="/images/financa7.jpg" class="card-img"/>

 

Aqui estamos usando a imagem financa7.jpg que foi incluída na pasta images criada dentro da pasta wwwroot.

Criando o componente Receitas e os DTOs

Vamos continuar trabalhando agora com o projeto Client.

Na pasta Pages crie um componente Razor chamado Receitas.razor :

@page "/receitas"

<div class="row">
    <div class="col-lg-8">
        <div class="card" >
            <div class="card-header" style="background-color: aqua; font-weight: bold ">
                Receitas
            </div>

            <div class="card-body">
                <table class="table table-striped">
                    <thead>
                        <tr>
                            <th>Data</th>
                            <th>Categoria</th>
                            <th>Descricao</th>
                            <th>Valor</th>
                        </tr>
                    </thead>

                    <tbody>
                        @if (receitas == null)
                        {
                            <tr><td><em>Carregando...</em></td></tr>
                        }
                        else
                        {
                            @foreach (var receita in receitas)
                            {
                                <tr>
                                    <td>@receita.Data.ToShortDateString()</td>
                                    <td>@receita.Categoria</td>
                                    <td>@receita.Descricao</td>
                                    <td align="right">@receita.Valor.ToString("C2",
                                              CultureInfo.CreateSpecificCulture("pt-BR"))</td>
                                </tr>

   
                        }
                        }
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
<div>&nbsp;</div>

@code {
    private Receita[] receitas;
}

Inicialmente montamos apenas o esqueleto do componente criando um card e uma tabela para exibir os dados das receitas. Executando o projeto e clicando no menu Receitas teremos a seguinte visão da aplicação:

Vamos agora criar o componente de formulário para poder incluir receitas.

Para isso vamos criar a pasta Components no projeto Client e a seguir criar nesta pasta duas classes: ReceitaDTO e DespesaDTO que vão representar os DTOs para os dados do modelo de domínio :

1- ReceitaDTO

using Financas.Pessoais.Shared;
using System;
using System.ComponentModel.DataAnnotations;
namespace Financas.Pessoais.Client.Components
{
    public class ReceitaDTO
    {
        [Required]
        public DateTime Data { get; set; }
        [Required]
        [StringLength(80)]
        public string Descricao { get; set; }
        [Required]
        public CategoriaReceita Categoria { get; set; }
        [Required]
        public decimal Valor { get; set; }
    }
}

2- DespesaDTO

using Financas.Pessoais.Shared;
using System;
using System.ComponentModel.DataAnnotations;
namespace Financas.Pessoais.Client.Components
{
    public class DespesaDTO
    {
        [Required]
        public DateTime Data { get; set; }
        [Required]
        [StringLength(80)]
        public string Descricao { get; set; }
        [Required]
        public CategoriaDespesa Categoria { get; set; }
        [Required]
        public decimal Valor { get; set; }
    }
}

Já estamos aplicando o recurso Data Annotations nestas classes pois elas serão usadas para validar a entrada de dados nos formulários Blazor que iremos criar a seguir.

Criando o formulário para Receita

Vamos criar na pasta Components o componente Razor ReceitaForm.razor que será o formulário usando para entrar com os dados das receitas. Para isso vamos usar o componente EditForm do Blazor que oferece recursos para entrada de dados.

@inject HttpClient Http;

<div class="card">
    <div class="card-header" style="background-color: aqua; font-weight: bold">
        Incluir receita
    </div>
    <div class="card-body">
        <EditForm Model="@receita" OnValidSubmit="@HandleValidSubmit">
            <DataAnnotationsValidator />
            <ValidationSummary />

            <div class="form-group">
                <label for="datainput">Data</label>
                <InputDate class="form-control" id="datainput" @bind-Value="receita.Data" />
            </div>
            <div class="form-group">
                <label for="descricaoinput">Descrição</label>
                <InputText class="form-control" id="descricaoinput" @bind-Value="receita.Descricao" />
            </div>
            <div class="form-group">
                <label for="categoriainput">Categoria</label>
                <InputSelect class="form-control" id="categoriainput" @bind-Value="receita.Categoria">
                    @{
                        foreach (var value in Enum.GetValues(typeof(CategoriaReceita)))
                        {
                            <option value="@value">@value</option>
                        }
                    }

                </InputSelect>
            </div>
            <div class="form-group">
                <label for="valorinput">Valor</label>
                <InputNumber class="form-control" id="valorinput" @bind-Value="receita.Valor" />
            </div>
            <div>
                <button type="submit" class="btn btn-primary">Enviar</button>
            </div>
        </EditForm>
    </div>
</div>

@code{

    private ReceitaDTO receita = new ReceitaDTO { Data = DateTime.Today };

    public async Task HandleValidSubmit()
    {

       //submeter formulario

    }

}

No componente ReceitaForm estamos usando o componente EditForm para montar o formulário com os dados a serem informados para as receitas. Para isso usamos os componentes : InputDate, InputSelect, InputText e InputNumber.

No formulário estamos definido o tipo a ser tratado como ReceitaDTO e no evento botão submit tratamos o evento HandleValidSubmit().

Executando o projeto teremos o seguinte resultado:

Para poder exibir dados no formulário e no componente Receitas teremos que implementar o Repositório e o Controlador no projeto Server e faremos isso na próxima parte do artigo.

Referências:


José Carlos Macoratti