00 / 05

RD Saúde: Apps Drogasil & Droga Raia
Time CORE dos apps da Drogasil e da Droga Raia, em funcionalidades críticas para conversão e experiência do usuário.
React Native, TypeScript, GraphQL, Node.js (BFF), MVVM, SOLID
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);
const flash = document.getElementById('flash');
let x = innerWidth * .5, y = innerHeight * .38;
let tx = x, ty = y;
const loop = () => {
x += (tx - x) * .14;
y += (ty - y) * .14;
flash.style.setProperty('--mx', x + 'px');
flash.style.setProperty('--my', y + 'px');
requestAnimationFrame(loop);
};
addEventListener('pointermove', e => {
tx = e.clientX;
ty = e.clientY;
}, { passive: true });
// sem ponteiro fino, a luz desce com a pagina
addEventListener('scroll', () => {
if (matchMedia('(pointer: fine)').matches) return;
const max = docEl.scrollHeight - innerHeight;
ty = innerHeight * (.2 + (scrollY / max) * .6);
}, { passive: true });
requestAnimationFrame(loop);Do código à produção: construo experiências web e mobile que chegam às mãos de quem usa.
Brasil
Trabalho em produto que já nasceu grande: código meu roda em apps de farmácia, de escola, de banco digital e de saúde.
Meu território é React Native e React com TypeScript, da arquitetura à entrega, passando por code review, BFF, GraphQL e a parte chata que ninguém posta no LinkedIn: teste, build quebrado e bug em produção às seis da tarde.
Gosto de interface bem resolvida e de decisão técnica que alguém consegue defender seis meses depois. Escrevo pensando em quem vai manter.

01 / 07
Projetos em que contribuí com desenvolvimento frontend e mobile
01 / 06
00 / 05

Time CORE dos apps da Drogasil e da Droga Raia, em funcionalidades críticas para conversão e experiência do usuário.
React Native, TypeScript, GraphQL, Node.js (BFF), MVVM, SOLID
01 / 05

Três frentes ao mesmo tempo: app do aluno, app da escola e a biblioteca de componentes.
React Native, TypeScript, Jest, Storybook, Component Library, Testes Automatizados
02 / 05

Um backoffice em Next.js que aposentou a planilha.
React, Next.js, TypeScript, Tailwind CSS, SCSS, NextAuth, Keycloak
03 / 05

Site institucional e app Android de uma plataforma de saúde digital.
React, React Native, JavaScript, TypeScript, APIs REST, Web & Mobile Integration
04 / 05

App interno de força de vendas em React Native e TypeScript.
React Native, TypeScript, Redux, Context API, Jest, CI/CD, Azure DevOps
05 / 05

Microfrontends aplicados ao mobile, que é onde a ideia fica difícil.
React Native, Expo, TypeScript, Microfrontends, Componentização, Design System
Ferramentas e tecnologias que utilizo no desenvolvimento
Vamos trabalhar juntos?
iniciando erika.lopes
idioma pt-BR
montando interface
pronto