From 34313e7214614b1214e9ba48b6cb58abad88786d Mon Sep 17 00:00:00 2001 From: Adarsh Jha <132337675+adarsh-jha-dev@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:32:10 +0530 Subject: [PATCH 1/4] Update Redeem.js --- submissions/chimoney-js/modules/Redeem.js | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/submissions/chimoney-js/modules/Redeem.js b/submissions/chimoney-js/modules/Redeem.js index 7fb25238..f977ba4c 100644 --- a/submissions/chimoney-js/modules/Redeem.js +++ b/submissions/chimoney-js/modules/Redeem.js @@ -120,6 +120,45 @@ async function chimoney(chimoneys, subAccount = null) { }); } +/** + * This function allows loyalty program members to redeem their earned rewards as Chimoney payouts + * @param {string} chiRef The Chi reference + * @param {object} loyaltyRewards An array of loyalty rewards to be redeemed as Chimoney payouts + * @param {string?} subAccount The subAccount of the transaction + * @returns The response from the Chi Money API + */ +async function loyalty(chiRef, loyaltyRewards, subAccount = null) { + // Define validation schema + const schema = Joi.object({ + chiRef: Joi.string().required(), // Chi reference should be a string and is required. + loyaltyRewards: Joi.array().items(Joi.object().keys({ + // Loyalty rewards should be an array of objects with specific properties. + rewardName: Joi.string().required(), // Define the properties of the loyalty reward. + rewardPoints: Joi.number().required(), + // Add more properties as needed for your loyalty rewards. + })).min(1).required(), // At least one loyalty reward is required. + subAccount: Joi.string().allow(null).optional(), // SubAccount is optional and can be a string or null. + }); + + // Validate input + const { value, error } = schema.validate( + { chiRef, loyaltyRewards, subAccount }, + { abortEarly: false } + ); + + if (error) throw new ValueError("input error(s)", formatJoiErrors(error)); + + const payload = { ...value }; + + if (subAccount) payload.subAccount = subAccount; + + return handleRequest({ + method: HTTPMETHODS.POST, + payload, + path: "/v0.2/redeem/loyalty", + }); +} + /** * This function allows you to redeem giftcard * @param {string} chiRef The Chi reference @@ -192,4 +231,5 @@ module.exports = { giftCard, any, chimoney, + loyalty, }; From 637debfe41d251142ae109daaba9e677e40a85de Mon Sep 17 00:00:00 2001 From: Adarsh Jha <132337675+adarsh-jha-dev@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:37:07 +0530 Subject: [PATCH 2/4] Update Redeem.js --- .../src/components/Redeem.js | 373 +++++++++--------- 1 file changed, 179 insertions(+), 194 deletions(-) diff --git a/submissions/chimoney-redeem-airtime/src/components/Redeem.js b/submissions/chimoney-redeem-airtime/src/components/Redeem.js index 0b767a56..24babe79 100644 --- a/submissions/chimoney-redeem-airtime/src/components/Redeem.js +++ b/submissions/chimoney-redeem-airtime/src/components/Redeem.js @@ -3,223 +3,208 @@ import React, { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import styled from 'styled-components'; import swal from 'sweetalert'; -import {API_KEY} from '../SecretKeys' - - +import { API_KEY } from '../SecretKeys'; const Redeem = () => { - const [errorMsg, seterrorMsg] = useState(''); - const [loading, setLoading] = useState(false); - const [countries, setCountries] = useState([]); - const [formDetails, setformDetails] = useState({ - chiRef: '', - countryToSend: '', - phoneNumber:'' + const [errorMsg, seterrorMsg] = useState(''); + const [loading, setLoading] = useState(false); + const [countries, setCountries] = useState([]); + const [formDetails, setformDetails] = useState({ + chiRef: '', + countryToSend: '', + phoneNumber: '', + }); + + const { id } = useParams(); + let validated = false; + + const getCountries = () => { + let config = { + method: 'GET', + url: 'https://api.chimoney.io/v0.2/info/airtime-countries', + headers: { 'X-API-Key': API_KEY }, + }; + axios(config) + .then(function (response) { + setCountries(response.data.data); + }) + .catch(function (error) { + console.log(error); + }); + }; + + useEffect(() => { + if (id) { + setformDetails({ + ...formDetails, + chiRef: id, + }); + } + getCountries(); + }, [id]); + + const handleChange = (e) => { + const { name, value } = e.currentTarget; + setformDetails({ + ...formDetails, + [name]: value, }); - - const { id } = useParams(); - let validated = false; - - const getCountries = () => { - let config = { - method: 'GET', - url: 'https://api.chimoney.io/v0.2/info/airtime-countries', - headers: {'X-API-Key': API_KEY } - }; - axios(config) - .then(function (response) { - setCountries(response.data.data) - // console.log(JSON.stringify(response.data.data)); - }) - .catch(function (error) { - console.log(error) - }); + }; + + const validateFormInput = () => { + let Phone = formDetails.phoneNumber; + + if (!formDetails.chiRef || !formDetails.countryToSend || !formDetails.phoneNumber) { + seterrorMsg('Please input all details'); + } else { + setLoading(true); + let firstDigit = Phone.slice(0, 1); + let CheckPhone = /^[+]*[(]{0,1}[0-9]{1,3}[)]{0,1}[-\s\./0-9]*$/g.test(Phone); + + if (firstDigit === '+' && CheckPhone) { + Phone = '+' + Phone.replace(/\D/g, ''); + validated = true; + } else { + setLoading(false); + seterrorMsg('Make sure your phone number follows the correct format'); + } } - - useEffect(() => { - if (id) { - setformDetails({ - ...formDetails, - chiRef: id - }) - } - getCountries() - }, [id]) - - - const handleChange = (e) => { - const { name, value } = e.currentTarget; - setformDetails({ - ...formDetails, - [name] : value + }; + + const handleSubmit = (e) => { + e.preventDefault(); + + validateFormInput(); + + if (validated) { + let config = { + method: 'POST', + url: 'https://api.chimoney.io/v0.2/redeem/loyalty', // Modify the endpoint for loyalty program redemption + headers: { 'X-API-Key': API_KEY }, + data: formDetails, + }; + axios(config) + .then(function (response) { + setLoading(false); + setformDetails({}); + swal({ + title: 'Loyalty Points Redeemed Successfully!', // Modify the success message + showClass: { + popup: 'animate__animated animate__fadeInDown', + }, + hideClass: { + popup: 'animate__animated animate__fadeOutUp', + }, + }); }) - console.log(formDetails) + .catch(function (error) { + setLoading(false); + seterrorMsg('Confirm the ticket is still valid'); + console.log(error); + }); } + }; - const validateFormInput = () => { - let Phone = formDetails.phoneNumber; - - if (!formDetails.chiRef || !formDetails.countryToSend || !formDetails.phoneNumber) { - console.log('error') - seterrorMsg('Please input all details') - } else { - setLoading(true) - //copy the first digit - let firstDigit = Phone.slice(0, 1); - - //check if it is a valid phone number - let CheckPhone = /^[+]*[(]{0,1}[0-9]{1,3}[)]{0,1}[-\s\./0-9]*$/g.test(Phone); - - //check if the first digit is "+" and it is a valid phone number - if (firstDigit === '+' && CheckPhone) { - - //remove unneccessary symbols from phone number and - // concatenate it with '+' to form a perfect phone number - Phone = '+' + Phone.replace(/\D/g, ''); - validated = true; - } else { - setLoading(false); - seterrorMsg('make sure your phone number follows the correct format') - } - } - } - - const handleSubmit = (e) => { - e.preventDefault(); - - validateFormInput(); - - if (validated) { - let config = { - method: 'POST', - url: 'https://api.chimoney.io/v0.2/redeem/airtime', - headers: {'X-API-Key': API_KEY }, - data: formDetails - }; - axios(config) - .then(function (response) { - // console.log(JSON.stringify(response.data)); - setLoading(false); - setformDetails({}); - swal({ - title: 'Airtime Redeemed Successfully!', - showClass: { - popup: 'animate__animated animate__fadeInDown' - }, - hideClass: { - popup: 'animate__animated animate__fadeOutUp' - } - }) - }) - .catch(function (error) { - setLoading(false); - seterrorMsg('confirm the ticket is still valid'); - console.log(error) - }); - } - } - - const clearErrorMsg = () => { - seterrorMsg('') - } + const clearErrorMsg = () => { + seterrorMsg(''); + }; return ( - -

Convert Chimoney to Airtime

-
- {errorMsg ?

{errorMsg}

: ''} - -
-

Ticket ID

- -
-
-

Phone number (+2349023..)

- -
-
-

Country

- - {/* */} -
-
- -
-
+ +

Redeem Loyalty Points

{/* Modify the title */} +
+ {errorMsg ?

{errorMsg}

: ''} + +
+

Ticket ID

+ +
+
+

Phone number (+2349023..)

+ +
+
+

Country

+ +
+
+ {/* Modify the button text */} +
+
-) -} + ); +}; const FormContainer = styled.div` - width: 100%; - height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - box-sizing: border-box; - color: white; - h1{ - text-align: center; - font-size: 2.5rem; - } - - form{ + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + box-sizing: border-box; + color: white; + h1 { + text-align: center; + font-size: 2.5rem; + } + + form { padding: 1rem; margin: 0 auto; width: 50vw; - /* box-shadow: 0 5px 5px 0px #70dfd6e4; */ - p{ - font-size: 1.2rem; - margin-bottom: 0.3rem; - } - .error{ - font-size: 1.1rem; - color: #1a04048f; - text-transform: capitalize; - padding: 1rem; - text-align: center; - font-weight: 600; + p { + font-size: 1.2rem; + margin-bottom: 0.3rem; } + .error { + font-size: 1.1rem; + color: #1a04048f; + text-transform: capitalize; + padding: 1rem; + text-align: center; + font-weight: 600; } + } - input, select{ + input, select { width: 50%; outline: none; font-size: 1.2rem; padding: 1rem; border: 1px solid #f8f8f8; background-color: #f8f8f8; - margin-bottom:2rem; - } - input{ - width: 90%; - } - .button{ - text-align: center; - width: 90%; - button{ - padding: 1rem 2rem; - box-shadow: 0 5px 5px 0px #70dfd6e4; - background: linear-gradient(135deg, rgba(142, 68, 173, 1) 0%, rgba(26, 188, 156, 1) 100%); - border: none; - text-transform: uppercase; - color: white; - font-size: 1rem; - transition: all ease-in 0.5secs; - font-weight: 600; - :hover{ - cursor: pointer; - font-size: 1.05rem; - } - } - + margin-bottom: 2rem; + } + input { + width: 90%; + } + .button { + text-align: center; + width: 90%; + button { + padding: 1rem 2rem; + box-shadow: 0 5px 5px 0px #70dfd6e4; + background: linear-gradient(135deg, rgba(142, 68, 173, 1) 0%, rgba(26, 188, 156, 1) 100%); + border: none; + text-transform: uppercase; + color: white; + font-size: 1rem; + transition: all ease-in 0.5secs; + font-weight: 600; + :hover { + cursor: pointer; + font-size: 1.05rem; + } } -` + } +`; -export default Redeem \ No newline at end of file +export default Redeem; From 0cdd05fa3f24dcf3eb296e74d419ec5374d5af03 Mon Sep 17 00:00:00 2001 From: Adarsh Jha <132337675+adarsh-jha-dev@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:40:04 +0530 Subject: [PATCH 3/4] Update Redeem.py --- .../Chimoney-Python/chimoney/Redeem.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/submissions/Chimoney-Python/chimoney/Redeem.py b/submissions/Chimoney-Python/chimoney/Redeem.py index f5cecc6b..d39dcec2 100644 --- a/submissions/Chimoney-Python/chimoney/Redeem.py +++ b/submissions/Chimoney-Python/chimoney/Redeem.py @@ -73,6 +73,36 @@ def any( return self._handle_request("POST", "/v0.2/redeem/any", payload) + def loyalty(self, chi_ref, loyalty_rewards, sub_account=None): + """ + This function handles the loyalty program redemption API. + + Args: + chi_ref(str): The Chimoney reference for the transaction. + loyalty_rewards(list): A list of dictionaries containing the details of loyalty rewards to be redeemed. + sub_account(str): The subaccount to be used. + + example: + loyalty_rewards = [ + { + "rewardName": "Loyalty Reward 1", + "rewardPoints": 100, + # Add more properties as needed for your loyalty rewards. + } + ] + + Return: + The JSON response from the Chimoney API. + """ + payload = { + "chiRef": chi_ref, + "loyaltyRewards": loyalty_rewards, + } + if sub_account: + payload["subAccount"] = sub_account + + return self._handle_request("POST", "/v0.2/redeem/loyalty", payload) + def chimoney(self, chimoneys, sub_account=None): """ This function handles the initiate chimoney API. From 159590c2793472b59c0ad581b916b69ad9de84b9 Mon Sep 17 00:00:00 2001 From: Adarsh Jha <132337675+adarsh-jha-dev@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:41:55 +0530 Subject: [PATCH 4/4] Update redeem.test.js --- submissions/chimoney-js/tests/redeem.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/submissions/chimoney-js/tests/redeem.test.js b/submissions/chimoney-js/tests/redeem.test.js index ec373ee4..69ed7de9 100644 --- a/submissions/chimoney-js/tests/redeem.test.js +++ b/submissions/chimoney-js/tests/redeem.test.js @@ -81,4 +81,20 @@ describe("Redeem", () => { expect(error).toBeInstanceOf(ValueError); } }); + + test("loyalty: should throw Chi Money Error", async () => { + try { + await redeem.loyalty("testref", []); + } catch (error) { + expect(error).toBeInstanceOf(ChiMoneyError); + } + }); + + test("loyalty: should throw value error", async () => { + try { + await redeem.loyalty(); + } catch (error) { + expect(error).toBeInstanceOf(ValueError); + } + }); });