Blog do Nex

Acompanhamento de metas ✅

Programação

janeiro 23, 2019

Então como planejado adicionei uma sessão para mostrar o acompanhamento das metas, pretendo ter no máximo 4 metas a serem acompanhadas, acho que mais que isso ficaria muito difícil e talvez deixando elas públicas assim eu me esforce mais para conseguir, pelo menos é o que espero hehe.

O desenho foi bem simples, procurei literalmente progress-bar react na internet e peguei alguns exemplos, achei esse artigo que ensina a fazer a sua própria e editei para as minhas necessidades How To Build A Progress Bar With React.

O resultado é esse: Barra de progresso

Gostei muito, achei bem simples e rápido, o código está dividido em 2 arquivos, 1 sendo somente a barra e o outro com o título, valor inicial e final, o primeiro chamei de progress-bar.js:

const Filler = (props) => {
  return (
    <div style={{
      width: `${props.percentage}%`,
      backgroundColor: '#419eda',
      height: '100%',
      borderRadius: 'inherit',
    }}
    />
  )
}

const ProgressBar = (props) => {
  return (
    <div style={{
      position: 'relative',
      height: 20,
      width: '100%',
      borderRadius: 50,
      overflow: 'hidden',
      backgroundColor: `#f4f9ff`,
    }}
    data-tip={props.tooltip}
    >
      <Filler percentage={props.percentage} />
    </div>
  )
}

O segundo de goal.js:

const getStrByType = (type, value) => {
  var result = `R\$${value}`
  if (type === 'weight') {
    result = `${value}kg`
  }

  return result
}

const Goal = (props) => {
  const { name, type, percentage, tooltip, start, goal } = props;

  return (
    <div style={{
      display: 'flex',
      flexDirection: 'column',
      padding: 5,
      width: '25%',
      minWidth: 160,
    }}
    >
      <ReactTooltip
	place="bottom"
	type="info"
	effect="float"
      />
      <p
	style={{
	  marginBottom: rhythm(1 / 4),
	  alignSelf: 'center',
	}}>
	{name}
      </p>
      <ProgressBar
	tooltip={getStrByType(type, tooltip)}
	percentage={percentage} />
      <div
	style={{
	  display: 'flex',
	  flexDirection: 'row',
	  justifyContent: 'space-between',
	}}>
	<p> {getStrByType(type, start)} </p>
	<p> {getStrByType(type, goal)} </p>
      </div>
    </div>
  )
}

Para fazer no browser ficarem os quatro em uma linha e no mobile somente dois por linha tive que fazer algumas modificações que não gostei muito, adicionei o minWidth: 160 no goal.js como pode ver acima e no componente que realiza a lista de goals coloquei o flexWrap: 'wrap'. Preferiria mesmo dizer que no browser eu quero width: '25%' e no mobile width: 50%', porém não encontrei forma simples de fazer isso, sempre adicionava uma biblioteca gigantesca ou coisas do tipo.

O problema foram os valores, eu não queria colocar nada hardcodded mas não sabia como fazer isso sem um banco de dados (visto que sempre montei aplicações full stack e é a primeira vez fazendo um wpa).

O stack do blog é bem simples, utilizo o Gatsby como framework e Netlify como serviço de hospedagem, escolhi o Gatsby porque tenho experiência com o React Native e pensei que possivelmente poderia ter uma transição bem tranquila para o Reactjs.

Para resolver o problema do update das metas eu pensei em uma estrutura de arquivos json, aonde tenho grupos de metas sendo os arquivos, algo como investing.json, metas e atualização das metas dentro desse arquivo, aqui vai um exemplo do arquivo citado:

{
  "name": "Investimento",
  "goals": [
    {
      "name": "Emergência",
      "goal": 24000,
      "type": "money",
      "start": 0,
      "updates": [
	{
	  "value": 1000,
	  "date": "2019-01-20T16:04:00.000Z"
	}
      ]
    },
    {
      "name": "Viagem",
      "goal": 5000,
      "type": "money",
      "start": 0,
      "updates": [
	{
	  "value": 500,
	  "date": "2019-01-22T18:47:23.000Z"
	}
      ]
    }
  ]
}

Assim para o componente ficar completo bastava eu realizar uma consulta a esses valores, por sorte o Gatsby tem um plugin muito útil para isso e trata os dados com um graphql excelente, o plugin é: gatsby-transformer-json Com pouquíssimas configurações pude realizar a query e acoplar ao meu componente, o componente que engloba tudo é o seguinte:

const calculateGoalTotal = goal => {
  var result = goal.updates.reduce((a, b) => {
    if (typeof a === 'number')
      a = { value: a }

    return a.value + b.value
  }, { value: 0 })

  if (typeof result !== 'number')
    result = 0

  return result
}

export default () => (
  <StaticQuery
    query={graphql`
      query {
	allGoalsJson {
	  edges {
	    node {
	      name
	      goals {
		name
		goal
		type
		start
		updates {
		  value
		  date
		}
	      }
	    }
	  }
	}
      }
    `}
    render={data => {
      const groups = data.allGoalsJson.edges

      return (
	<div
	  style={{
	    display:'flex',
	    flexDirection: 'row',
	    justifyContent: 'space-between',
	    flexWrap: 'wrap',
	    justifyContent: 'center',
	  }}
	>
	  {groups.map(({ node }, index) => {
	    const { goals } = node

	    return goals.map((goal) => {
	      const total = calculateGoalTotal(goal)
	      const objective = goal.start - goal.goal
	      const percent = (total * 100) / objective

	      return (
		<Goal
		  name={goal.name}
		  percentage={Math.floor(Math.abs((percent)))}
		  tooltip={total}
		  start={goal.start}
		  type={goal.type}
		  goal={goal.goal}
		  key={goal.name}
		/>
	      )
	    })
	  })}
	</div>
      )
    }}
  />
)

Utilizei também do StaticQuery para realizar consultas dentro de um componente ao invez de uma página, não é um dos meus melhores códigos mas fiquei orgulhoso com o resultado. Agora consigo de forma simples monitorar meus objetivos, certo? Ainda não!

Seria muito ruim eu ter que toda vez abrir o arquivo de investimento, ir para a linha correta que quero preencher, colocar os dados que quero e assegurar que estão corretos. Eu possuo um pequeno script em bash para criar posts, também poderia sem problema nenhum adicionar funções para setar esses valores para mim.

Eu logo o fiz, esse aqui é o output da ajuda do script:

bm blog manager by Tnex <[email protected]>
		Usage:
		bm r:	run dev
		bm p:	new post
		bm g:	new goal group
		bm n:	new goal
		bm u:	new goal update

Não irei colocar o código fonte aqui para o post não ficar gigantesco cheio de códigos, porém você pode vê-lo no Github.

Com isso as metas sim estão completas! Fácil manutenção e atualização, eu ia falar nesse post sobre o bot do telegram mas deixarei para o próximo pois já está ficando muito grande. Até a próxima!


Newsletter 📬

Inscreva-se a baixo para ser notificado de atualizações! Não se preocupe, todas elas são escritas a mão e com muito carinho 💕

Seu email não será compartilhado com ninguém.

Opa! Eai? 🙋🏻‍♂️

Aqui é o Nex! Sou um programador que está tentando entender o que é essa coisa de vida, eu escrevo basicamente sobre projetos e melhoria pessoal.

Caso queira falar comigo basta deixar um Oi! Você também pode me encontrar no Github ou LinkedIn.