Remitt

International Money Transfer Comparison Platform

The Challenge

I developed a complete remittance comparison platform from scratch using React 17 with JavaScript, Express.js and MongoDB. The application integrates the TransferWise API to get real-time data from more than 20 financial providers, including traditional banks and fintechs like Wise, Western Union, Remitly and WorldRemit. I implemented an authentication system with user registration, email notifications with Nodemailer, and a responsive interface with dark/light mode using Tailwind CSS.

Tech Stack

Frontend

React 17
JavaScript
Tailwind CSS
Context API

Backend

Express.js
Axios
Nodemailer
OAuth2

Database

MongoDB

Tools

TransferWise API

Technical Challenges Overcome

Complex External API Integration

Challenge:

Integrate the TransferWise API to get real-time data from multiple remittance providers with different response formats and error handling.

Solution:

I created a custom API service with Axios that handles TransferWise API queries, implemented robust error handling and data validation before showing results to the user.

Result:

Reliable system that processes real-time remittance queries with more than 20 financial providers and handles API errors elegantly.

User Experience Optimization

Challenge:

Create an intuitive interface that allows non-technical users to easily compare complex remittance options with different fees and exchange rates.

Solution:

I implemented a simplified form with country selectors with flags, real-time validation, loading states with custom spinner, and clear visual results showing fees and amounts received.

Result:

Interface that reduces the complexity of comparing remittances to a few clicks, with clear visual feedback and intuitive navigation.

Country and Provider Data Management

Challenge:

Handle an extensive database of countries with their currencies, base64 flags, and multiple financial providers with different URLs and configurations.

Solution:

I created structured JSON files for countries and providers, implemented a data mapping system that connects countries with currencies and providers with their corresponding URLs.

Result:

Scalable system that handles more than 100 countries and 20+ financial providers with updated data and easy maintenance.

Featured Functionalities

Real-time Comparison Engine

System that queries multiple financial providers simultaneously, calculates current fees and exchange rates, and presents results ordered by best value for the user.

Advanced Country Selector

Component with more than 100 countries, base64 flags, names in Spanish and English, and intelligent search that facilitates selection of origin and destination country.

Dynamic Theme System

Implementation of dark/light mode with React Context API, user preference persistence, and smooth transitions between themes with adaptive icons.

Registration and Notification System

User registration with email validation, automatic notification system via email using Nodemailer and OAuth2, and session management.

Complete Responsive Design

Adaptive interface that works perfectly on mobile, tablet and desktop, with hamburger navigation, responsive cards and optimization for different screen sizes.

Project Results

3 weeks
Development Time
20+
Financial Providers Integrated
100+
Countries Supported
React, Express.js, MongoDB, Tailwind CSS
Main Technologies

Featured Code

External API Integration with Error Handling

Robust service that handles TransferWise API queries with data validation and elegant error handling.

// API service for remittance queries
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 getting exchange rates');
    }
  }
  
  validateAndFormatRates(data) {
    return data.providers
      .filter(provider => provider.rate > 0)
      .sort((a, b) => a.totalCost - b.totalCost);
  }
}

Country Selector with Base64 Flags

Interactive component with more than 100 countries, base64 flags, and intelligent search.

// Country selector component with flags
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>
  );
};

Theme System with Context API

Complete theme system with localStorage persistence and smooth transitions.

// Context for theme management
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>
  );
};

// Custom hook to use theme
export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
};
Cristian Perdomo - Desarrollador Full Stack