Build a Simple HR Platform with the Payout Chimoney Endpoint.

This tutorial will guide you through the process of building a simple HR platform that allows HRs to payout employees using the Payout Chimoney Endpoint.

Prerequisites

  • Basic knowledge of JavaScript, React, and Node.js
  • Node.js and npm installed on your machine
  • A text editor, such as Visual Studio Code
  • A Chimoney API key (see how to create one here )

Step 1: Create a New React App

  1. Open your terminal.
  2. Run the following command to create a new React app named hr-platform:
    npx create-react-app hr-platform
    

Step 2: Set Up the Server

  1. Create a server folder in the root directory of the project and add a server.js file
  2. Navigate to your server directory and initialize a new Node.js project by running npm init -y in your terminal.
  3. Install the necessary dependencies by running npm install dotenv express nodemailer cors @chimoney/v0.2.3.
  4. Create a .env file in the server directory of your project and add your environment variables:
REACT_APP_API_KEY=your_chimoney_api_key
API_BASE_URL=your_api_base_url
EMAIL_USER=your_email_user
EMAIL_PASS=your_email_password
PORT=5000

Step 3: Implement the Payout Endpoint in Server

  1. In the server directory, add a server.js file
  2. In the server.js file, require the necessary modules and set up the Express app.

require("dotenv").config();
const express = require("express");
const sdk = require("@api/chimoney");
const nodemailer = require("nodemailer");
const cors = require("cors");

const app = express();
app.use(express.json());
app.use(cors());

  1. Initialize the Chimoney SDK with your API key and server URL.
sdk.auth(process.env.REACT_APP_API_KEY);
sdk.server(process.env.API_BASE_URL);

  1. Create a POST endpoint /payout to handle payout requests.
app.post("/payout", async (req, res) => {
  const { email, valueInUSD, currency } = req.body;

  try {
    const response = await sdk.postV02PayoutsChimoney({
      chimoneys: [{ email, valueInUSD, currency }],
    });

    let transporter = nodemailer.createTransport({
      service: "gmail",
      auth: {
        user: process.env.EMAIL_USER,
        pass: process.env.EMAIL_PASS,
      },
    });

    let info = await transporter.sendMail({
      from: '"Chimoney" <[email protected]>',
      to: email,
      subject: "Chimoney Payout",
      text: `You have received a payout. Redeem it here: ${response.data.paymentLink}`,
    });

    console.log("Email sent: %s", info.messageId);

    res.json({ status: "success", data: response.data });
  } catch (error) {
    console.error("Error during payout:", error);

    console.error(error.stack);

    res.status(500).json({
      status: "error",
      message: "Error when trying to payout",
      error: error.message,
      stack: error.stack,
    });
  }
});


  1. Start the server to listen on the specified port.
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Step 4: Set Up the Client-side

  1. Navigate back to your project's root directory.
  2. Install Axios by running npm install axios.
  3. Replace the contents of App.js with the following code:
import React, { useState } from "react";
import "./App.css";
import axios from "axios";

function App() {
  const [isPaymentSuccessful, setIsPaymentSuccessful] = useState(null);
  const [showPayoutForm, setShowPayoutForm] = useState(false);
  const [recipients, setRecipients] = useState([
    { email: "", currency: "USD", amount: "" },
  ]);

  const handleInputChange = (index, event) => {
    const newRecipients = [...recipients];
    newRecipients[index][event.target.name] = event.target.value;
    setRecipients(newRecipients);
  };

  const handlePayout = async (event) => {
    event.preventDefault();

    try {
      for (let recipient of recipients) {
        const response = await axios.post("http://localhost:5000/payout", {
          email: recipient.email,
          valueInUSD: recipient.amount,
          currency: recipient.currency,
        });

        if (response.data.status !== "success") {
          console.error("Payment failed for recipient:", recipient);
          setIsPaymentSuccessful(false);
          return;
        }
      }

      console.log("Payment successful!");
      setIsPaymentSuccessful(true);
    } catch (error) {
      console.error("Payment failed!", error);
      setIsPaymentSuccessful(false);
    }

    setTimeout(() => {
      setIsPaymentSuccessful(null);
    }, 5000);
  };

  const handleShowPayoutForm = () => {
    setShowPayoutForm(true);
  };

  const handleAddRecipient = () => {
    setRecipients([...recipients, { email: "", currency: "USD", amount: "" }]);
  };

  const handleRemoveRecipient = (index) => {
    const newRecipients = recipients.filter((_, i) => i !== index);
    setRecipients(newRecipients);
  };

  return (
    <div className="App">
      <header className="App-header">
        <h1>Welcome HR!</h1>
        <p>Manage your employee payouts here.</p>
        {!showPayoutForm && (
          <button onClick={handleShowPayoutForm}>Pay Employees</button>
        )}
        {showPayoutForm && (
          <form onSubmit={handlePayout}>
            {recipients.map((recipient, index) => (
              <div key={index} className="recipient-box">
                <button
                  type="button"
                  className="remove-recipient"
                  onClick={() => handleRemoveRecipient(index)}
                >
                  &times;
                </button>
                <label htmlFor={`email-${index}`}>Employee Email</label>
                <input
                  type="email"
                  id={`email-${index}`}
                  name="email"
                  value={recipient.email}
                  onChange={(e) => handleInputChange(index, e)}
                  required
                />
                <label htmlFor={`currency-${index}`}>Currency</label>
                <select
                  id={`currency-${index}`}
                  name="currency"
                  value={recipient.currency}
                  onChange={(e) => handleInputChange(index, e)}
                >
                  <option value="USD">USD</option>
                  <option value="CAD">CAD</option>
                  <option value="NGN">NGN</option>
                </select>
                <label htmlFor={`amount-${index}`}>Amount</label>
                <input
                  type="number"
                  id={`amount-${index}`}
                  name="amount"
                  value={recipient.amount}
                  onChange={(e) => handleInputChange(index, e)}
                  required
                />
              </div>
            ))}
            <button
              type="button"
              onClick={handleAddRecipient}
              className="add-recipient"
            >
              + Add a Recipient
            </button>
            <button type="submit">Pay Employees</button>
          </form>
        )}
        {isPaymentSuccessful !== null && (
          <div className="payout-message">
            {isPaymentSuccessful ? (
              <h2 className="success">Congratulations, Payout sent!</h2>
            ) : (
              <h3 className="error">Error when paying out.</h3>
            )}
          </div>
        )}
      </header>
    </div>
  );
}

export default App;

To style the application, you can add this styling to your App.css code:

@import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@700&display=swap");

body {
  margin: 0;
  font-family: "Comfortaa", sans-serif;
  background-color: #ffffff;
  color: #333;
}

.App {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 20px;
}

.App-header {
  background-color: #f2f3f4;
  padding: 40px;
  border-radius: 8px;
  box-shadow: 0 12px 16px rgba(63, 58, 58, 0.1);
  text-align: center;
  color: white;
  width: 100%;
  max-width: 600px;
}

h1 {
  font-size: 2.5em;
  margin-bottom: 0.5em;
  color: #746f6f;
}

p {
  font-size: 1.2em;
  margin-bottom: 1.5em;
  color: #746f6f;
}

button {
  background-color: #02b975;
  color: #ffffff;
  font-size: 1em;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

button:hover {
  background-color: #378638;
}

form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  max-width: 400px;
  margin: 20px auto;
}

input,
select {
  width: 90%;
  padding: 10px;
  margin-bottom: 1.5em;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 0.9em;
  font-family: "Comfortaa", sans-serif;
  color: #746f6f;
}

input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
  font-family: "Comfortaa", sans-serif;
  font-size: 0.8em;
  color: #746f6f;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.payout-message {
  margin-top: 20px;
  padding: 10px;
  border-radius: 4px;
  width: 100%;
  text-align: center;
}

.success {
  color: #4caf50;
  background-color: #e8f5e9;
}

.error {
  color: #f44336;
  background-color: #ffebee;
}
.add-recipient {
  background-color: #02b975;
  margin-bottom: 20px;
}

.add-recipient:hover {
  background-color: #28a745;
}

.payout-message {
  margin-top: 20px;
}

.success {
  color: green;
}

.error {
  color: red;
}

.recipient {
  margin-bottom: 20px;
}
.separator {
  border: none;
  height: 1px;
  background-color: #02b975;
  margin: 20px 0;
}
.recipient-box {
  background: #f9f9f9;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(22, 21, 21, 0.1);
  margin-bottom: 20px;
  position: relative;
}

.recipient-box label {
  color: #333;
}

.remove-recipient {
  background: transparent;
  border: none;
  color: #ff0000;
  font-size: 20px;
  top: -20px;
  right: -24px;
  cursor: pointer;
  position: absolute;
}

.remove-recipient:hover {
  color: #cc0000;
}

Step 5: Run the Application

  1. Start the server by running node server.js in the server directory of your project.
  2. Start the client by navigating to the root directory and running npm start.

You should now have a simple HR platform that allows HRs to pay employees using the Chimoney API.

Demo Platform

This platform includes a form for entering employee information and a button for initiating payouts. After a payout is initiated, the platform sends an email to the employee with a link to redeem their payout.

Link to Demo Platform