00 / 05

RD Saúde: Drogasil & Droga Raia Apps
CORE team on the Drogasil and Droga Raia apps, on features critical to conversion and user experience.
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);From code to production: I build web and mobile experiences that reach the hands of the people who use them.
Brazil
I work on products that were already big when I arrived: my code runs in pharmacy, school, digital banking and health apps.
My ground is React Native and React with TypeScript, from architecture to delivery, through code review, BFF, GraphQL and the dull part nobody posts about: tests, broken builds and a production bug at six in the evening.
I like an interface that is properly resolved and a technical decision someone can still defend six months later. I write for whoever maintains it next.

01 / 07
Projects I contributed to with frontend and mobile development
01 / 06
00 / 05

CORE team on the Drogasil and Droga Raia apps, on features critical to conversion and user experience.
React Native, TypeScript, GraphQL, Node.js (BFF), MVVM, SOLID
01 / 05

Three fronts at once: the student app, the school app and the component library.
React Native, TypeScript, Jest, Storybook, Component Library, Testes Automatizados
02 / 05

A Next.js backoffice that retired the spreadsheet.
React, Next.js, TypeScript, Tailwind CSS, SCSS, NextAuth, Keycloak
03 / 05

Institutional site and Android app for a digital health platform.
React, React Native, JavaScript, TypeScript, APIs REST, Web & Mobile Integration
04 / 05

Internal sales force app in React Native and TypeScript.
React Native, TypeScript, Redux, Context API, Jest, CI/CD, Azure DevOps
05 / 05

Microfrontends applied to mobile, which is where the idea gets hard.
React Native, Expo, TypeScript, Microfrontends, Componentização, Design System
Tools and technologies I use in development
Let’s work together?
booting erika.lopes
locale en
mounting interface
ready