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:
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!
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.