Jump to content
eiwes

Como posso melhorar esse código javascript encapsulado e usando método imutável?

Recommended Posts

Eu tenho esse código, mas preciso retornar funções puras em vez de funções mutáveis.

 

É possível? Talvez usando OOP? Não sei como melhorar isso.

 

Tentei retornar os valores de cada função, mas não obtive sucesso.

 

import { AssetStatusType } from '@domain/interfaces/common'

import {
  BothComponentType,
  ComponentsType,
  GroupFiltersType,
  OperationType,
  OverviewModelType,
  PendenciesOverviewType,
  PendenciesType,
  StructurePendenciesCount,
  StructureStatusCount
} from '../../types'

const updateStatusCount = (
  statusCount: StructureStatusCount,
  status: AssetStatusType
) => {
  statusCount[status] = (statusCount[status] || 0) + 1
}

const updatePendenciesCount = (
  pendenciesCount: StructurePendenciesCount,
  key: AssetStatusType,
  subKey: OperationType | PendenciesOverviewType
) => {
  pendenciesCount[key] = pendenciesCount[key] ?? {}
  pendenciesCount[key][subKey] = (pendenciesCount[key]?.[subKey] || 0) + 1
}

const processOverviewPendencies = (
  pendencies: PendenciesType[] | null | undefined,
  pendenciesCount: StructurePendenciesCount,
  countedIds: Set<string>,
  id: string
) => {
  if (pendencies?.length) {
    for (const { state, pendencyType } of pendencies) {
      const uniqueId = `${state}-${pendencyType}-${id}`
      if (!countedIds.has(uniqueId)) {
        updatePendenciesCount(pendenciesCount, state, pendencyType)

        countedIds.add(uniqueId)
      }
    }
  }
}

const processOverviewComponents = (
  components: ComponentsType[],
  isGroupByTree: boolean,
  statusCount: StructureStatusCount,
  pendenciesCount: StructurePendenciesCount,
  countedIds: Set<string>,
  id: string,
  type: BothComponentType
) => {
  for (const { pendencies, status, operationType } of components) {
    if (isGroupByTree && type === 'location') {
      updateStatusCount(statusCount, status)

      if (operationType) {
        updatePendenciesCount(pendenciesCount, status, operationType)
      }
    }
    processOverviewPendencies(pendencies, pendenciesCount, countedIds, id)
  }
}

const processOverviewData = (
  data: OverviewModelType[],
  groupBy: GroupFiltersType,
  statusCount: StructureStatusCount,
  pendenciesCount: StructurePendenciesCount,
  countedIds: Set<string>
) => {
  const isGroupByTree = groupBy === 'tree'
  const isGroupByAsset = groupBy === 'asset'

  for (const { id, status, components, operationType, type } of data) {
    if (isGroupByAsset || type === 'asset') {
      updateStatusCount(statusCount, status)
      if (operationType) {
        updatePendenciesCount(pendenciesCount, status, operationType)
      }
    }

    processOverviewComponents(
      components,
      isGroupByTree,
      statusCount,
      pendenciesCount,
      countedIds,
      id,
      type
    )
  }
}

export const calculateOverviewCounts = (
  data: OverviewModelType[],
  groupBy: GroupFiltersType
) => {
  const statusCount: StructureStatusCount = {} as StructureStatusCount
  const pendenciesCount: StructurePendenciesCount =
    {} as StructurePendenciesCount

  const countedIds = new Set<string>()

  processOverviewData(data, groupBy, statusCount, pendenciesCount, countedIds)

  return { ...statusCount, pendencies: pendenciesCount }
}

Existe uma maneira mais limpa e elegante de fazer isso? Preciso retornar um objeto como este:

// calculateOverviewCounts return this

{
    pendencies: StructurePendenciesCount;
    working: number;
    inAlert: number;
    warning: number;
    stopped: number;
    off: number;
}

StructurePendenciesCount é:

image.thumb.png.515970af4c98d649ef0da98710a0b233.png

Share this post


Link to post
Share on other sites

 

Para tornar o código mais limpo, modular e orientado a objetos (OOP), podemos encapsular as funcionalidades em classes e usar métodos para operar sobre os estados internos dos objetos. Isso torna o código mais organizado oque facilita a manutenção e compreensão.

Vou reestruturar seu código.

Classe OverviewCounter -> Esta classe conterá a lógica para contar os status e as pendências.
Classe ComponentProcessor -> Esta classe será responsável por processar os componentes e pendências.
Classe OverviewProcessor -> Esta classe usará as classes acima para processar os dados de visão geral e calcular as contagens.


 

import { AssetStatusType } from '@domain/interfaces/common'
import {
  BothComponentType,
  ComponentsType,
  GroupFiltersType,
  OperationType,
  OverviewModelType,
  PendenciesType,
  StructurePendenciesCount,
  StructureStatusCount
} from '../../types'

class OverviewCounter {
  private statusCount: StructureStatusCount = {} as StructureStatusCount;
  private pendenciesCount: StructurePendenciesCount = {} as StructurePendenciesCount;

  updateStatusCount(status: AssetStatusType) {
    this.statusCount[status] = (this.statusCount[status] || 0) + 1;
  }

  updatePendenciesCount(key: AssetStatusType, subKey: OperationType | PendenciesOverviewType) {
    this.pendenciesCount[key] = this.pendenciesCount[key] ?? {};
    this.pendenciesCount[key][subKey] = (this.pendenciesCount[key]?.[subKey] || 0) + 1;
  }

  getStatusCount(): StructureStatusCount {
    return this.statusCount;
  }

  getPendenciesCount(): StructurePendenciesCount {
    return this.pendenciesCount;
  }
}

class ComponentProcessor {
  private counter: OverviewCounter;
  private countedIds: Set<string>;

  constructor(counter: OverviewCounter, countedIds: Set<string>) {
    this.counter = counter;
    this.countedIds = countedIds;
  }

  processPendencies(pendencies: PendenciesType[] | null | undefined, id: string, state: AssetStatusType) {
    if (pendencies?.length) {
      for (const { pendencyType } of pendencies) {
        const uniqueId = `${state}-${pendencyType}-${id}`;
        if (!this.countedIds.has(uniqueId)) {
          this.counter.updatePendenciesCount(state, pendencyType);
          this.countedIds.add(uniqueId);
        }
      }
    }
  }

  processComponents(components: ComponentsType[], isGroupByTree: boolean, id: string, type: BothComponentType) {
    for (const { pendencies, status, operationType } of components) {
      if (isGroupByTree && type === 'location') {
        this.counter.updateStatusCount(status);

        if (operationType) {
          this.counter.updatePendenciesCount(status, operationType);
        }
      }
      this.processPendencies(pendencies, id, status);
    }
  }
}

class OverviewProcessor {
  private counter: OverviewCounter;
  private countedIds: Set<string>;

  constructor() {
    this.counter = new OverviewCounter();
    this.countedIds = new Set<string>();
  }

  processOverviewData(data: OverviewModelType[], groupBy: GroupFiltersType) {
    const componentProcessor = new ComponentProcessor(this.counter, this.countedIds);
    const isGroupByTree = groupBy === 'tree';
    const isGroupByAsset = groupBy === 'asset';

    for (const { id, status, components, operationType, type } of data) {
      if (isGroupByAsset || type === 'asset') {
        this.counter.updateStatusCount(status);
        if (operationType) {
          this.counter.updatePendenciesCount(status, operationType);
        }
      }

      componentProcessor.processComponents(components, isGroupByTree, id, type);
    }
  }

  getResults() {
    return { ...this.counter.getStatusCount(), pendencies: this.counter.getPendenciesCount() };
  }
}

export const calculateOverviewCounts = (data: OverviewModelType[], groupBy: GroupFiltersType) => {
  const processor = new OverviewProcessor();
  processor.processOverviewData(data, groupBy);
  return processor.getResults();
};

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By belann
      Olá!
       
      Estou usando o editor quill em uma página html, sem fazer a instalação com npm, mas usando as api´s via internet com http, no entanto não consigo fazer a tecla enter funcionar para mudança de linha, tentei essa configuração abaixo, mas não funcionou.
       
      modules: {       syntax: true,       toolbar: '#toolbar-container',       keyboard: {         bindings: {           enter: {             key: 13,             handler: function(range, context) {                       quill.formatLine(range.index, range.length, { 'align': '' });             }           }  
       
    • By violin101
      Caros amigos, saudações.
       
      Gostaria de poder tirar uma dúvida com os amigos.
       
      Como faço uma função para Comparar a Data Digitada pelo o Usuário com a Data Atual ?

      Data Digitada:  01/09/2024
       
      Exemplo:
      25/09/2024 é menor que DATA Atual  ====> mensagem: informe uma data válida.
      25/09/2024 é igual DATA Atual ===> o sistema libera os INPUT's.
       
      Como faço uma comparação com a Data Atual, para não Deixar Gravar Data retroativa a data Atual.
       
      Grato,
       
      Cesar
    • By Rafael Castelhano
      Olá, quero preencher um dict dinamicamente onde a chave é uma string multidimencional no dict, ex:
      var dict = {} var path = 'a.b.c' dict[path] = 55 // isso faz dict ficar desta forma {'a.b.c': 55} // mais quero que fique assim {a: {b: {c: 55}}} Como consigo alterar desta forma? 
    • By violin101
      Caros amigos, saudações.
       
      Estou com um problema de cálculo que não estou conseguindo resolver.
       
      Tenho uma rotina em Javascript que faz o seguinte cálculo qtde x vrUnit = total.
       
      qtde   x  vrUnit    =    total
      1,23   x  1,00       =    1,23    << até aqui tudo bem.
       
      o problema seria fazer o arredondamento para cima para impedir de fazer este cálculo:
      0,01 x 0,01 = 0,0001
       
      para digitar o valor estou utilizando esta função:
       
      /*Esta função quando o usuário digitar o valor aparece * 1,23 */ function formataDigitacao(i) { //Adiciona os dados para a másrcara var decimais = 2; var separador_milhar = '.'; var separador_decimal = ','; var decimais_ele = Math.pow(10, decimais); var thousand_separator = '$1'+separador_milhar; var v = i.value.replace(/\D/g,''); v = (v/decimais_ele).toFixed(decimais) + ''; var splits = v.split("."); var p_parte = splits[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, thousand_separator); (typeof splits[1] === "undefined") ? i.value = p_parte : i.value = p_parte+separador_decimal+splits[1]; } /*Esta função faz a multiplicação entre Valor Unitário X Quantidade *faz a multiplicação correta */ function calcProd(){ //Obter valor digitado do produto var prod_qtde = document.getElementById("qtde").value; //Remover ponto e trocar a virgula por ponto while (prod_qtde.indexOf(".") >= 0) { prod_qtde = prod_qtde.replace(".", ""); } prod_qtde = prod_qtde.replace(",","."); //Obter valor digitado do produto var valor_unit = document.getElementById("vlrunit").value; //Remover ponto e trocar a virgula por ponto while (valor_unit.indexOf(".") >= 0) { valor_unit = valor_unit.replace(".", ""); } valor_unit = valor_unit.replace(",","."); //Calcula o Valor do Desconto if (valor_unit > 0 && prod_qtde > 0) { calc_total_produto = (parseFloat(valor_unit) * parseFloat(prod_qtde)); var numero = calc_total_produto.toFixed(2).split('.'); //<<== aqui faço o arredondamento das casas decimais de 1,234 p/ 1,23 numero[0] = numero[0].split(/(?=(?:...)*$)/).join('.'); document.getElementById("vlrtotal").value = numero.join(','); } else { if (valor_unit > 0) { document.getElementById("vlrtotal").value = document.getElementById("vlrunit").value; } else { document.getElementById("vlrtotal").value = "0,00"; } } } Grato,
       
      Cesar
    • By violin101
      Caros amigos, saudações.
       
      Estou com uma dúvida e não estou conseguindo resolver.
       
      Tenho um SELECT onde eu pego o ID e NOME_CAMPO, até aqui tudo bem.
       
      Para evitar erros de saída de produtos por estoque, preciso passar o ID do Centro de Custo, para gerar a Tabela de produtos em estou por cada centro de Custo.

      Exemplo:
      Centro de Custo 1 - tem:
      produto A | produto B | produto C

      Centro de Custo 2 - tem:
      produto D | produto E

      Como consigo pegar via JAVASCRIPT o código do Centro de Custo selecionado e passar para a Controller, para chamar a MODAL ?

      meu código está assim:
      VIEW
       
      <div class="col-md-6"> <label for="deptsOrigem">Dpto Origem:</label> <div class="input-group mb-3"> <input type="hidden" name="idCentrocusto" id="idCentrocusto"> <input type="text" class="form-control" id="nameCentrocusto" name="nameCentrocusto" style="font-size:15px; font-weight:bold;" placeholder="Pesquisar por Centro de Custo" disabled> <span class="input-group-btn"> <button class="btn btn-primary" type="button" id="btnOrgn" name="btnOrgn" data-toggle="modal" data-target="#modal_deptsOrigem" > <span class="fa fa-search"></span> Buscar </button> </span> </div> </div> <div class="modal fade" id="modal_deptsOrigem"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header" style="font-size:18px; color:#ffffff; background:#307192;"> <h4 class="modal-title"><strong>Lista do(s) Centro de Custo(s)</strong></h4> </div> <div class="modal-body"> <table id="deptsLista" class="table table-bordered table-hover"> <thead> <tr> <th style="text-align:center;">Código</th> <th style="text-align:center;">Centro de Custo(s)</th> <th style="text-align:center;">Ação</th> </tr> </thead> <tbody id="itensDeptos"> <!---Monta Tabela VIA Ajax---> </tbody> </table> </div> <div class="modal-footer justify-content-center" style="background:#BBAAAA;"> <button type="button" class="btn btn-danger pull-center" data-dismiss="modal">Voltar</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div>  
      o JAVASCRIPT está assim:
       
      //Função para Chamar o Centro de Custo que o usuário deseja. listaDeptos(); var table = $('#deptsLista').dataTable({ "searching": true, "ordering": true, "info": true, "autoWidth": false, "pageLength": 5, "lengthMenu": [ 5, 10, 25, 50 ], "responsive": true, }); // list all employee in datatable function listaDeptos(){ $.ajax({ type : 'ajax', url : '<?=base_url()?>estoque/consumo/deptsList/', async : false, dataType : 'json', success : function(data){ var html = ''; var i; for(i=0; i<data.length; i++){ var datadpts = data[i].idDepartamento+"*"+data[i].departamento; html += '<tr>'+ '<td width="15%" style="text-align:center; font-size:16px;">'+data[i].idDepartamento+'</td>'+ '<td width="50%" style="text-align:left; font-size:16px;">'+data[i].departamento+'</td>'+ '<td width="10%" style="text-align:center;">'+ '<button type="button" class="btn btn-success btn_orgns" style="margin-right: 1%; padding: 2px 5px;" title="Selecionar Departamento" value="'+datadpts+'"><span class="fa fa-check"></span></button>'+ '</td>'+ '</tr>'; } //Fim - For $('#itensDeptos').html(html); } //Fim - success }); //Fim - ajax } //Fim - function /*---Função para Capturar o Departamento selecionado---*/ $(document).on("click",".btn_orgns",function(){ dpts = $(this).val(); infodpts = dpts.split("*"); $("#idCentrocusto").val(infodpts[0]); $("#nameCentrocusto").val(infodpts[1]); $("#modal_deptsOrigem").modal("hide"); //Função para Atualizar o Status do Botão statusPesqProd(); }); //Função para Gerar a Lista de Produtos por Centro de Custo via AJAX. listaProduts(); var table = $('#prdsLista').dataTable({ "searching": true, "ordering": true, "info": true, "autoWidth": false, "pageLength": 5, "lengthMenu": [ 5, 10, 25, 50 ], "responsive": true, }); // list all employee in datatable function listaProduts(){ $.ajax({ type : 'ajax', url : '<?=base_url()?>estoque/consumo/produtsList/', //< como passo aqui o ID do Centro de Custo Selecionado para Gerar a Lista de Produtos async : false, dataType : 'json', success : function(data){ var html = ''; var i; for(i=0; i<data.length; i++){ var prds = data[i].idProdutos+"*"+data[i].cod_interno+"*"+data[i].descricao+"*"+data[i].prd_unid+"*"+data[i].estoque_atual; html += '<tr>'+ '<td width="15%" style="text-align:center; font-size:16px;">'+data[i].cod_interno+'</td>'+ '<td width="50%" style="text-align:left; font-size:16px;">'+data[i].descricao+'</td>'+ '<td width="15%" style="text-align:center; font-size:16px;">'+data[i].prd_unid+'</td>'+ '<td width="15%" style="text-align:center; font-size:16px;">'+data[i].estoque_atual+'</td>'+ '<td width="12%" style="text-align:center;">'+ '<button type="button" class="btn btn-success btn-prod" style="margin-right: 1%; padding: 2px 5px;" title="Selecionar Produto" value="'+prds+'"><span class="fa fa-check"></span></button>'+ '</td>'+ '</tr>'; } //Fim - For $('#itensProds').html(html); } //Fim - success }); //Fim - ajax } //Fim - function  
      a CONTROLLER está assim:
      //Função para Criar Lista - Produtos Data Tables com AJAX function produtsList(){ $data = $this->consumo_model->prodsList(); echo json_encode($data); }  
       
       
      Grato,
       
      Cesar
×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.