Desarrollé una plataforma completa de comparación de remesas desde cero utilizando React 17 con JavaScript, Express.js y MongoDB. La aplicación integra la API de TransferWise para obtener datos en tiempo real de más de 20 proveedores financieros, incluyendo bancos tradicionales y fintechs como Wise, Western Union, Remitly y WorldRemit. Implementé un sistema de autenticación con registro de usuarios, notificaciones por email con Nodemailer, y una interfaz responsive con modo oscuro/claro usando Tailwind CSS.
Integrar la API de TransferWise para obtener datos en tiempo real de múltiples proveedores de remesas con diferentes formatos de respuesta y manejo de errores.
Creé un servicio de API personalizado con Axios que maneja las consultas a la API de TransferWise, implementé manejo de errores robusto y validación de datos antes de mostrar resultados al usuario.
Sistema confiable que procesa consultas de remesas en tiempo real con más de 20 proveedores financieros y maneja errores de API de forma elegante.
Crear una interfaz intuitiva que permita a usuarios no técnicos comparar fácilmente opciones complejas de remesas con diferentes comisiones y tasas de cambio.
Implementé un formulario simplificado con selectores de países con banderas, validación en tiempo real, estados de carga con spinner personalizado, y resultados visuales claros mostrando comisiones y cantidades recibidas.
Interfaz que reduce la complejidad de comparar remesas a unos pocos clicks, con feedback visual claro y navegación intuitiva.
Manejar una base de datos extensa de países con sus monedas, banderas en base64, y múltiples proveedores financieros con diferentes URLs y configuraciones.
Creé archivos JSON estructurados para países y proveedores, implementé un sistema de mapeo de datos que conecta países con monedas y proveedores con sus URLs correspondientes.
Sistema escalable que maneja más de 100 países y 20+ proveedores financieros con datos actualizados y fácil mantenimiento.
Sistema que consulta múltiples proveedores financieros simultáneamente, calcula comisiones y tasas de cambio actuales, y presenta los resultados ordenados por mejor valor para el usuario.
Componente con más de 100 países, banderas en base64, nombres en español e inglés, y búsqueda inteligente que facilita la selección del país origen y destino.
Implementación de modo oscuro/claro con Context API de React, persistencia de preferencias del usuario, y transiciones suaves entre temas con iconos adaptativos.
Registro de usuarios con validación de email, sistema de notificaciones automáticas por correo electrónico usando Nodemailer y OAuth2, y gestión de sesiones.
Interfaz adaptativa que funciona perfectamente en móviles, tablets y desktop, con navegación hamburguesa, cards responsivas y optimización para diferentes tamaños de pantalla.
Servicio robusto que maneja consultas a la API de TransferWise con validación de datos y manejo de errores elegante.
// Servicio de API para consultas de remesas
const axios = require('axios');
class RemittanceService {
async getRates(fromCountry, toCountry, amount) {
try {
const response = await axios.get(`${API_BASE_URL}/rates`, {
params: { from: fromCountry, to: toCountry, amount }
});
return this.validateAndFormatRates(response.data);
} catch (error) {
console.error('API Error:', error.message);
throw new Error('Error al obtener tasas de cambio');
}
}
validateAndFormatRates(data) {
return data.providers
.filter(provider => provider.rate > 0)
.sort((a, b) => a.totalCost - b.totalCost);
}
}Componente interactivo con más de 100 países, banderas en base64 y búsqueda inteligente.
// Componente de selector de países con banderas
const CountrySelector = ({ countries, onSelect, placeholder }) => {
const [searchTerm, setSearchTerm] = useState('');
const filteredCountries = countries.filter(country =>
country.name.toLowerCase().includes(searchTerm.toLowerCase())
);
return (
<div className="relative">
<input
type="text"
placeholder={placeholder}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full p-3 border rounded-lg focus:ring-2 focus:ring-blue-500"
/>
<div className="absolute z-10 w-full mt-1 bg-white border rounded-lg shadow-lg">
{filteredCountries.map(country => (
<div
key={country.code}
onClick={() => onSelect(country)}
className="flex items-center p-3 hover:bg-gray-100 cursor-pointer"
>
<img
src={`data:image/png;base64,${country.flag}`}
alt={country.name}
className="w-6 h-4 mr-3"
/>
<span>{country.name}</span>
</div>
))}
</div>
</div>
);
};Sistema completo de temas con persistencia en localStorage y transiciones suaves.
// Context para manejo de temas
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState(() => {
const savedTheme = localStorage.getItem('theme');
return savedTheme || 'light';
});
useEffect(() => {
document.documentElement.classList.toggle('dark', theme === 'dark');
localStorage.setItem('theme', theme);
}, [theme]);
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// Hook personalizado para usar el tema
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
};