Building a Currency Exchange and Swap Feature in React Native

In this blog post, we will focus on the implementation of the currency exchange and swap feature in a React Native application. This feature enables users to convert an amount from one currency to another with real-time exchange rates and also allows them to effortlessly swap the selected currencies. We will cover setting up the project, fetching data from an API, managing state, and building a user-friendly UI to facilitate the currency exchange and swap.

Prerequisites Before we dive into building the currency exchange and swap feature, ensure you have the following prerequisites:

  1. Knowledge of React Native and JavaScript programming.

  2. Familiarity with React Native components, state, and useEffect hook.

  3. Node.js and npm installed on your development machine.

  4. A working React Native project with necessary dependencies already set up.

Setting Up the Project

  1. Create a new React Native project using the Expo CLI or React Native CLI.

  2. Install the required dependencies: react, react-native, @expo/vector-icons, react-native-text-ticker, react-native-modal, and any other components you'd like to use.

Fetching Data and State Management In this step, we'll fetch data from an API and manage the state of the currency exchange feature.

// Import necessary modules and components
import React, { useState, useEffect, useContext } from 'react';
import { StyleSheet, Text, View, TouchableOpacity, ScrollView, TextInput } from 'react-native';
import { AntDesign, FontAwesome, MaterialCommunityIcons, Ionicons } from '@expo/vector-icons';
import TextTicker from 'react-native-text-ticker';
import Modal from 'react-native-modal';


const HomeScreen = ({ navigation }) => {
  // Get the logged-in user from the AuthContext

  const [data, setData] = useState([]);



  useEffect(() => {
    fetchData();

    // Periodically fetch updated data every 5 seconds
    const interval = setInterval(fetchData, 5000);

    // Clean up the interval on component unmount
    return () => clearInterval(interval);

  }, []);



};

export default HomeScreen;

Creating the Currency Exchange and Swap Feature Now, let's create the currency exchange and swap feature along with the necessary UI components:

// ... (previous code)

const HomeScreen = ({ navigation }) => {
  // ... (previous code)

  // State variables for the currency exchange and swap feature
  const [modalVisible, setModalVisible] = useState(false);
  const [modalVisible1, setModalVisible1] = useState(false);
  const [selectedCurrency, setSelectedCurrency] = useState('NGN');
  const [selectedCurrency1, setSelectedCurrency1] = useState('KSH');
  const [selectedExchange1, setSelectedExchange1] = useState('');
  const [selectedExchange2, setSelectedExchange2] = useState('');
  const [t1, setT1] = useState('');
  const [t2, setT2] = useState('');

  // Handlers for selecting currencies from the modal
  const handleSelectCurrencyPress = () => {
    setModalVisible(!modalVisible);
  };

  const handleSelectCurrencyPress1 = () => {
    setModalVisible1(!modalVisible1);
  };

  const handleCurrencySelect = (currencies) => {
    setSelectedCurrency(currencies);

    // Swap the currencies when the user selects a different currency
    if (currencies === 'NGN') {
      setSelectedCurrency('NGN');
      setSelectedCurrency1('KSH');
    } else if (currencies === 'KSH') {
      setSelectedCurrency('KSH');
      setSelectedCurrency1('NGN');
    }

    setModalVisible(!modalVisible);
  };

  const handleCurrencySelect1 = (currencies) => {
    setSelectedCurrency1(currencies);

    // Swap the currencies when the user selects a different currency
    if (currencies === 'KSH') {
      setSelectedCurrency('NGN');
      setSelectedCurrency1('KSH');
    } else if (currencies === 'NGN') {
      setSelectedCurrency('KSH');
      setSelectedCurrency1('NGN');
    }

    setModalVisible1(!modalVisible1);
  };

  // Handler for swapping the selected currencies
  const handleSwap = () => {
    // Swap the values of selectedCurrency and selectedCurrency1
    const tempCurrency = selectedCurrency;
    setSelectedCurrency(selectedCurrency1);
    setSelectedCurrency1(tempCurrency);
  };

  // ... (continue with the rest of the code)
};

Building the User Interface (UI) Let's create the UI components for the currency exchange and swap feature:

// ... (previous code)

const HomeScreen = ({ navigation }) => {
  // ... (previous code)

  return (
    <>
      <View style={styles.container}>
        <View style={styles.flex1}>
          <ScrollView>
            {/* ... (previous code) */}
            <View style={styles.section3}>
              <View style={styles.section31}>
                <View style={{ width: '55%' }}>
                  <Text style={styles.labels}>Amount of {selectedCurrency || 'NGN'}</Text>
                  <TextInput
                    placeholder='Amount'
                    style={styles.sizer}
                    autoCapitalize="none"
                    required={true}
                    keyboardType="numeric"
                    value={selectedExchange1}
                    onChangeText={(text) => {
                      setSelectedExchange1(text);
                      setT1(text);
                    }}
                  />
                </View>
                <TouchableOpacity style={styles.swapbutt} onPress={handleSelectCurrencyPress}>
                  <Text>{selectedCurrency || 'NGN'}  <AntDesign name="caretdown" size={15} color="black" /></Text>
                </TouchableOpacity>
              </View>
              {/* ... (other UI elements) */}
            </View>
          </ScrollView>
        </View>
        <Bottom navigation={navigation} />
      </View>
      {/* Currency selection modals */}
      <Modal
        isVisible={modalVisible}
        onBackdropPress={() => setModalVisible(false)}
        style={styles.modalContainer}


        backdropOpacity={0}
      >
        {/* ... (modal content for selecting currency) */}
      </Modal>
      <Modal
        isVisible={modalVisible1}
        onBackdropPress={() => setModalVisible1(false)}
        style={styles.modalContainer}
        backdropOpacity={0}
      >
        {/* ... (modal content for selecting currency) */}
      </Modal>
    </>
  );
};

export default HomeScreen;

Complete Code:


import React from 'react';
import { useState, useEffect, useContext } from 'react'
import { StyleSheet, Text, View, TouchableOpacity, ScrollView, TextInput } from 'react-native';
import { AntDesign, FontAwesome, FontAwesome5, MaterialCommunityIcons, Ionicons } from '@expo/vector-icons';
import Bottom from '../components/Bottom';
import { AuthContext } from '../components/AuthContext';
import TextTicker from 'react-native-text-ticker';
import Carousel from '../components/Carousel';
import Modal from 'react-native-modal';

const HomeScreen = ({ navigation }) => {
  const { loggedInUser } = useContext(AuthContext);
  const [data, setData] = useState([]);
  const mobilePhone = loggedInUser.phone;
  const uniqueId = loggedInUser.uniqueId;

  useEffect(() => {
    fetchData();

  // Periodically fetch updated data every 5 seconds
  const interval = setInterval(fetchData, 5000);

  // Clean up the interval on component unmount
  return () => clearInterval(interval);

  }, []);

  const fetchData = async () => {
    try {




      const response = await fetch(`https://yourwebsite.com/myfolder/site.php?phone=${encodeURIComponent(mobilePhone)}&uniqueId=${encodeURIComponent(uniqueId)}`);
      const jsonData = await response.json();
      setData(jsonData);
    } catch (error) {
      console.error(error);
    }
  };
  const Naira = data.length > 0 ? data[0].Naira : '';
  const Mpesa = data.length > 0 ? data[0].Mpesa : '';
  const firstName = data.length > 0 ? data[0].firstname : '';
  const lastName = data.length > 0 ? data[0].lastname : '';
  const id = data.length > 0 ? data[0].id : '';




  const [modalVisible, setModalVisible] = useState(false);
  const [modalVisible1, setModalVisible1] = useState(false);
  const [selectedCurrency, setSelectedCurrency] = React.useState('NGN');

  const [selectedCurrency1, setSelectedCurrency1] = React.useState('KSH');


  const [selectedExchange1, setSelectedExchange1] =  React.useState('');
  const [selectedExchange2, setSelectedExchange2] =  React.useState('');
  const [t1, setT1] = useState('');

  const [t2, setT2] = useState('');

  const [t3, setT3] = useState('');

  const handleSelectCurrencyPress = () => {
    setModalVisible(!modalVisible);
  };

  const handleSelectCurrencyPress1 = () => {
    setModalVisible1(!modalVisible1);
  };

  const handleCurrencySelect = (currencies) => {

    setSelectedCurrency(currencies);

  if (currencies === 'NGN') {
    setSelectedCurrency('NGN');
    setSelectedCurrency1('KSH');
  } 
  if (currencies === 'KSH') {
    setSelectedCurrency('KSH');
    setSelectedCurrency1('NGN');
  } 



  setModalVisible(!modalVisible);
  };


  const handleCurrencySelect1 = (currencies) => {

    setSelectedCurrency1(currencies);

  if (currencies === 'KSH') {
    setSelectedCurrency('NGN');
    setSelectedCurrency1('KSH');
  } 
  if (currencies === 'NGN') {
    setSelectedCurrency('KSH');
    setSelectedCurrency1('NGN');
  } 



  setModalVisible1(!modalVisible1);
  };




  const mycurrency = [
    'NGN',
    'KSH',

    // Add more currency here
  ];

  const handleSwap = () => {
    // Swap the values of selectedCurrency and selectedCurrency1
    const tempCurrency = selectedCurrency;
    setSelectedCurrency(selectedCurrency1);
    setSelectedCurrency1(tempCurrency);
  };

  useEffect(() => {
    if (selectedCurrency === 'NGN') {
      // Convert the input strings to numbers for addition
      const amount1 = parseFloat(t1);

     // const amount2 = parseFloat(t2);

      // Check if the inputs are valid numbers
      if (!isNaN(amount1)) {
        // Perform the addition and store the result in t3
        const convertedAmount = amount1 * 0.184907;
        setSelectedExchange2(convertedAmount.toFixed(2)); // Round to 2 decimal places
      } else {
        // Clear t3 if the inputs are not valid numbers
        setSelectedExchange2('');
      }
    }
    if (selectedCurrency === 'KSH') {
      // Convert the input strings to numbers for addition
      const amount1 = parseFloat(t1);

     // const amount2 = parseFloat(t2);

      // Check if the inputs are valid numbers
      if (!isNaN(amount1)) {
        // Perform the addition and store the result in t3
        const convertedAmount = amount1 * 5.4103;
        setSelectedExchange2(convertedAmount.toFixed(2)); // Round to 2 decimal places
      } else {
        // Clear t3 if the inputs are not valid numbers
        setSelectedExchange2('');
      }
    }

  }, [selectedCurrency, t1]);



  useEffect(() => {
    if (selectedCurrency1 === 'NGN') {
      // Convert the input strings to numbers for addition
      const amount2 = parseFloat(t2);

     // const amount2 = parseFloat(t2);

      // Check if the inputs are valid numbers
      if (!isNaN(amount2)) {
        // Perform the addition and store the result in t3
        const convertedAmount = amount2 * 0.184907;
        setSelectedExchange1(convertedAmount.toFixed(2)); // Round to 2 decimal places
      } else {
        // Clear t3 if the inputs are not valid numbers
        setSelectedExchange1('');
      }
    }
    if (selectedCurrency1 === 'KSH') {
      // Convert the input strings to numbers for addition
      const amount2 = parseFloat(t2);

     // const amount2 = parseFloat(t2);

      // Check if the inputs are valid numbers
      if (!isNaN(amount2)) {
        // Perform the addition and store the result in t3
        const convertedAmount = amount2 * 5.4103;
        setSelectedExchange1(convertedAmount.toFixed(2)); // Round to 2 decimal places
      } else {
        // Clear t3 if the inputs are not valid numbers
        setSelectedExchange1('');
      }
    }

  }, [selectedCurrency1, t2]);


  return (
    <>
    <View style={styles.container}>

      <View style={styles.flex1}>
        <ScrollView>


          <View style={styles.section0}>
            <View style={styles.section01}>
              <Carousel />
            </View>
            <View style={styles.section02}>
              <View>
                <Ionicons name="megaphone-outline" size={30} color="black" />
              </View>
              <View>
                <TextTicker
                  style={styles.marqueeText}
                  loop
                  bounce
                  repeatSpacer={50}
                  marqueeDelay={1000}
                  speed={10} // Increase the speed value
                >Send money effortlessly between Kenya and Nigeria with Naira2Mpesa. Fast, secure, and reliable transfers at your fingertips. Experience seamless cross-border money transfers with Naira2Mpesa. Connect with loved ones in Kenya and Nigeria instantly</TextTicker>
              </View>
            </View>
          </View>

          <View style={styles.section1}>
            <View style={styles.flexy}>
              <TouchableOpacity onPress={() => navigation.navigate('Profile')}>
                <FontAwesome name="money" size={20} color="black" />
              </TouchableOpacity>
              <Text> N{Naira} </Text>
            </View>
            <View style={styles.line} />
            <View style={styles.flexy}>
              <TouchableOpacity onPress={() => navigation.navigate('Transaction')}>
                <FontAwesome5 name="money-bill" size={20} color="black" />
              </TouchableOpacity>
              <Text> KSH {Mpesa} </Text>
            </View>
          </View>




          <View style={styles.section2}>

            <TouchableOpacity onPress={() => navigation.navigate('Deposit')} style={styles.butt1}>
              <Text style={styles.gameq}>Deposit</Text>
            </TouchableOpacity>

            <TouchableOpacity onPress={() => navigation.navigate('Withdraw')} style={styles.butt2}>
              <Text style={styles.gameq}>Withdraw </Text>
            </TouchableOpacity>




          </View>


          <View style={styles.section3}>

            <View style={styles.section31}>




              <View style={{ width: '55%' }}>
                <Text style={styles.labels}>Amount of {selectedCurrency || 'NGN'}</Text>

<TextInput
  placeholder='Amount'
  style={styles.sizer}
  autoCapitalize="none"
  required={true}
  keyboardType="numeric"
  value={selectedExchange1}
  onChangeText={(text) => {
    // Update the selectedExchange1 state with the text value
    setSelectedExchange1(text);
    // Also update the t1 variable with the text value
   setT1(text);
  }}
/>

              </View>


              <TouchableOpacity style={styles.swapbutt} onPress={handleSelectCurrencyPress}>
                <Text>{selectedCurrency || 'NGN'}  <AntDesign name="caretdown" size={15} color="black" /></Text>

              </TouchableOpacity>


            </View>


            <TouchableOpacity style={styles.section32} onPress={handleSwap}>
              <MaterialCommunityIcons name="swap-vertical" size={30} color="black" />
            </TouchableOpacity>

            <View style={styles.section311}>




              <View style={{ width: '55%' }}>
                <Text style={styles.labels}>Amount of {selectedCurrency1 || 'KSH'}</Text>
                <TextInput
    placeholder='Amount'
    style={styles.sizer}
    autoCapitalize="none"
    required={true}
keyboardType="numeric"
    value={selectedExchange2}
    onChangeText={(text) => {
      // Update the selectedExchange1 state with the text value
      setSelectedExchange2(text);
      // Also update the t1 variable with the text value
      setT2(text);
    }}
  />


              </View>


              <TouchableOpacity style={styles.swapbutt} onPress={handleSelectCurrencyPress1}>
                <Text>{selectedCurrency1 || 'KSH'}   <AntDesign name="caretdown" size={15} color="black" /></Text>

              </TouchableOpacity>


            </View>


            <TouchableOpacity onPress={() => navigation.navigate('Transaction')} style={styles.butt3}>
              <Text style={styles.text1}>Swap Currency</Text>
            </TouchableOpacity>


            <Text style={styles.rateText}>
          1 NGN = 0.184907 KSH
        </Text>
        <Text style={styles.rateText}>
          1 KSH = 5.4103 NGN
        </Text>


          </View>







        </ScrollView>


      </View>

      <Bottom navigation={navigation} />




    </View>
    <Modal
        isVisible={modalVisible}
        onBackdropPress={() => setModalVisible(false)}
        style={styles.modalContainer}
        backdropOpacity={0} // Set the backdropOpacity to 0 (transparent)
      >
        <View style={styles.modalme}>
          <Text style={styles.testcurrency}>Select Currency</Text>
          <ScrollView contentContainerStyle={styles.scroller} showsVerticalScrollIndicator={false}>
            {mycurrency.map((currencies) => (
              <TouchableOpacity key={currencies} onPress={() => handleCurrencySelect(currencies)}>
                <Text style={styles.mytexty}>{currencies}</Text>
              </TouchableOpacity>
            ))}
          </ScrollView>
        </View>
      </Modal>

      <Modal
        isVisible={modalVisible1}
        onBackdropPress={() => setModalVisible1(false)}
        style={styles.modalContainer}
        backdropOpacity={0} // Set the backdropOpacity to 0 (transparent)
      >
        <View style={styles.modalme}>
          <Text style={styles.testcurrency}>Select Currency</Text>
          <ScrollView contentContainerStyle={styles.scroller} showsVerticalScrollIndicator={false}>
            {mycurrency.map((currencies) => (
              <TouchableOpacity key={currencies} onPress={() => handleCurrencySelect1(currencies)}>
                <Text style={styles.mytexty}>{currencies}</Text>
              </TouchableOpacity>
            ))}
          </ScrollView>
        </View>
      </Modal>
    </>
  );
}

export default HomeScreen



const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#cccccc',
    flexDirection: 'column',

  },
  flex1: {
    flex: 8,


    backgroundColor: '#00cccc',




  },
  flex2: {
    flex: 1,


    backgroundColor: 'red',
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',

  },
  section1: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'center',
    gap: 20,
    marginTop: 30,
  },

  flexy: {
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    gap: 5,
  },


  line: {
    width: 1,
    height: '100%',
    backgroundColor: 'black',
    marginHorizontal: 10,
  },

  section2: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'center',
    gap: 20,
    marginTop: 30,
  },
  butt1: {
    backgroundColor: 'white',
    width: '39%',
    borderRadius: 5,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 18,
    marginBottom: 30,
  },
  butt2: {
    backgroundColor: 'white',
    width: '39%',
    borderRadius: 5,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 18,
    marginBottom: 30,
  },
  section3: {

    marginTop: 30,
    borderWidth: 1,
    height: 500,
    marginLeft: 40,
    marginRight: 40,
    paddingLeft: 10,
    paddingRight: 10,

  },
  sizer: {
    borderWidth: 1,
    height: 50,
    width: '100%',
    fontSize: 18,
    paddingLeft: 20,
    borderRadius: 5,
    borderColor: 'white',
    color: 'white',
  },
  section31: {

    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',

    //gap: 10,
    marginTop: 60,

  },
  section311: {

    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',

    //gap: 10,
    marginTop: 40,

  },
  labels: {
    position: 'absolute',
    top: -25,
  },
  section32: {
    width: 40,
    height: 60,
    borderWidth: 1,
    borderRadius: 100,
    marginLeft: 120,
    marginTop: 25,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center'

  },
  butt3: {
    backgroundColor: 'white',
    width: '100%',
    borderRadius: 5,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 18,
    marginTop: 30,

  },
  text1: {
    fontWeight: 600,
    fontSize: 18
  },
  gameq: {
    fontWeight: 600
  },
  section0: {
    borderWidth: 1,
    width: '100%',
    height: 250,
  },
  section01: {
    flex: 3,
    backgroundColor: 'blue',
    alignItems: 'center',
    justifyContent: 'center',
  },

  section02: {
    flex: 1,
    backgroundColor: 'yellow',
    display: 'flex',
    flexDirection: 'row',
    alignItems: 'center',
    gap: 3,
    borderLeftWidth: 10,
    overflow: 'hidden', // Add this line
  },

  marqueeText: {
    fontSize: 16,
    fontWeight: 'bold',
    color: 'black',
  },
  swapbutt:{
width: '40%',
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,


  },
  modalContainer: {

    borderWidth: 0,
    position: 'absolute',
    height: 'auto',
    width: '100%',
    bottom: '50%',
    borderTopRightRadius: 0,
    borderTopLeftRadius: 0,
   backgroundColor: 'pink',
    margin: 'auto',
    padding: 50,
    paddingTop: 100,


  },
  modalme: {
     borderWidth: 0,


  },
  scroller: {
    display: 'flex',
    alignItems: 'center',
    gap: 20
  },

  mytexty: {
    fontSize: 20,
  },
  responseMessage: {
    color: 'red',
  },
  errorMessage: {
    color: 'red',
  },
  testcurrency:{
    fontSize: 16,
    textAlign: 'center',
    marginBottom: 20,
    color: 'red'

  },
  rateText: {
    marginTop: 20,
    fontSize: 16,
    color: 'black',
    textAlign: 'center'
  },
});

Conclusion In this blog post, we successfully built a currency exchange and swap feature in a React Native application. Users can now convert amounts between different currencies and swap the selected currencies effortlessly. We covered how to fetch data from an API, manage the state of the currency exchange feature, and create a user-friendly UI using React Native components.

Feel free to customize the UI, add error handling, and integrate real currency exchange APIs to make the feature more robust. This currency exchange feature could be an excellent addition to any finance or money transfer application, enabling users to seamlessly exchange currencies at their fingertips.

Thank you for reading this blog post.

0
Subscribe to my newsletter

Read articles from Ogunuyo Ogheneruemu B directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ogunuyo Ogheneruemu B
Ogunuyo Ogheneruemu B

I'm Ogunuyo Ogheneruemu Brown, a senior software developer. I specialize in DApp apps, fintech solutions, nursing web apps, fitness platforms, and e-commerce systems. Throughout my career, I've delivered successful projects, showcasing strong technical skills and problem-solving abilities. I create secure and user-friendly fintech innovations. Outside work, I enjoy coding, swimming, and playing football. I'm an avid reader and fitness enthusiast. Music inspires me. I'm committed to continuous growth and creating impactful software solutions. Let's connect and collaborate to make a lasting impact in software development.