What is the best way to handle paystack implementation without a third party package? - javascript

I am building a React Native application and I am using Nodejs, MYSQL and Expo React Native. I am implementing payment with paystack for the first time. I followed their API guide which is found here for Node.js based application.
This is my code implementation:
export const httpBuyAction = async(req: Request, res: Response)=>{
//create a new instance of payment
const paystack = new PaymentSystem(sanitizedConfig.PAYSTACK_KEY);
const multiplyCartSum = cart.dataValues.cart_total_sum as number * 100;
const convertAmount = multiplyCartSum.toString()
const paymentDetails = {
email: user.dataValues.user_email as string,
amount: convertAmount as string
}
const response = await paystack.initializePayment(paymentDetails);
if(response?.response?.data?.status == false){
return res.status(response.response.status).json(response.response.data.message)
}
return res.status(200).json(response.data.data.authorization_url)
}
This code returns paystack web payment link and I used React Native Linking package to navigate to the paystack external link. This is the code:
const [paymentAuthorization, {data: paymentData, isLoading: isPaymentLoading, isSuccess: isPaymentSuccess,}]= usePaymentAuthorizationMutation();
const handlePayment = async ()=>{
dispatch(updateBackgroundLoader(true))
await paymentAuthorization()
}
I used react useEffect to trigger the action to navigate to the paystack payment portal.
useEffect(()=>{
const handlePaymentView = async()=>{
if(isPaymentSuccess){
const supportedURL = paymentData;
const supported = await Linking.canOpenURL(supportedURL);
if(supported){
dispatch(updateBackgroundLoader(false))
await Linking.openURL(supportedURL);
}else{
dispatch(updateBackgroundLoader(false))
dispatch(updateNotification(true));
dispatch(updateError('Unsupported link, contact admin'))
}
}else{
dispatch(updateBackgroundLoader(false))
}
}
handlePaymentView()
}, [isPaymentLoading])
It works but I don't know if this is better than using a third party package. Also, I noticed that the link surely takes the user away from the app, how do I return the user to the app after payment? Is it possible?

Related

Hooks.js running the db connection and results twice in sveltekit

I'm using sveltekit and trying to understand all the new features added after retiring Sapper. One of those new features is hooks.js which runs on the server and not accessible to the frontend. It makes dealing with db safe. So I created a connection to my mongodb to retrieve user's data before I use the db results in my getSession function. It works but I noticed that it access my database TWICE. Here is my hooks.js code:
import * as cookie from 'cookie';
import { connectToDatabase } from '$lib/mongodb.js';
export const handle = async ({event, resolve})=>{
const dbConnection = await connectToDatabase();
const db = dbConnection.db;
const userinfo = await db.collection('users').findOne({ username: "a" });
console.log("db user is :" , userinfo) //username : John
const response = await resolve(event)
response.headers.set(
'set-cookie', cookie.serialize("cookiewithjwt", "sticksafterrefresh")
)
return response
}
export const getSession = (event)=>{
return {
user : {
name : "whatever"
}
}
}
The console.log you see here returns the user data twice. One as soon as I fire up my app at localhost:3000 with npm run dev and then less than a second, it prints another console log with the same information
db user is : John
a second later without clicking on anything a second console.log prints
db user is : John
So my understanding from the sveltekit doc is that hooks.js runs every time SvelteKit receives a request. I removed all prerender and prefetch from my code. I made sure I only have the index.svelte in my app but still it prints twice. My connection code I copied from an online post has the following:
/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
Here is my connection code:
import { MongoClient } from 'mongodb';
const mongoURI ="mongodb+srv://xxx:xxx#cluster0.qjeag.mongodb.net/xxxxdb?retryWrites=true&w=majority";
const mongoDB = "xxxxdb"
export const MONGODB_URI = mongoURI;
export const MONGODB_DB = mongoDB;
if (!MONGODB_URI) {
throw new Error('Please define the mongoURI property inside config/default.json');
}
if (!MONGODB_DB) {
throw new Error('Please define the mongoDB property inside config/default.json');
}
/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = global.mongo;
if (!cached) {
cached = global.mongo = { conn: null, promise: null };
}
export const connectToDatabase = async() => {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true
};
cached.promise = MongoClient.connect(MONGODB_URI).then((client) => {
return {
client,
db: client.db(MONGODB_DB)
};
});
}
cached.conn = await cached.promise;
return cached.conn;
So my question is : is hooks.js runs twice all the time, one time on the server and one time on the front? If not, then why the hooks.js running/printing twice the db results in my case?
Anyone?

Github user finder api, how to return multiple users per search? JS

Hello I am using github api to create github user finder. my question is how to manipulate on api link to get users which include e.target.value of the searchbar and not only that one that exactly matches.
here is my code
const [finalData, setFinalData] = useState([]);
const handleSearch = async (e) => {
try {
const URL = `https://api.github.com/users/${e.target.value}?
client_id=e25d1dbedde5215999ef&client_secret=ee080580b7c4f19688ccaef6844c3fe88bb811d`;
Promise.all([fetch(URL).then((res) => res.json())]).then((data) => {
if (data) {
setData(data);
}
});
} catch (err) {
console.log(err);
}
};
const setData = (data) => {
data && setFinalData(data);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
You can use the Search users endpoint. There is a query parameter (q) that allows you to use multiple search criteria documented here
Here's an example using Octokit, but if you still want to use fetch, the endpoint should be https://api.github.com/search/users
Note: I really hope the client secret you are exposing here is for a test application.
Search GitHub users                                                                                
View in Fusebit
const userSearch = ''; // Specify the search text here
const usersResponse = await octokit.rest.search.users({
q: userSearch,
per_page:100
});
const { total_count, items } = usersResponse.data;
console.log(`Listing ${items.length} users of ${total_count} \n`, items.map(user => user.login));

Why is my data import to Algolia search using the API script timing out

I am trying to implement single index searching using Algoliasearch for my iOS mobile app. I have about 110 users on my application. However, when I upload their data to Algolia search's index the function times out before uploading all users. Instead it throws an Error message in the http browser and declares a timeout in the Firestore console.
Firestore console:
sendCollectionToAlgolia
Function execution took 60044 ms, finished with status: 'timeout'
I created the function using this tutorial:
https://medium.com/#soares.rfarias/how-to-set-up-firestore-and-algolia-319fcf2c0d37
Although i have ran into some complications, I highly recommend that tutorial if you have your app using swiftUI iOS platform and implement cloud functions using Typescript.
Heres my function:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import algoliasearch from 'algoliasearch';
admin.initializeApp();
const db = admin.firestore();
const algoliaClient = algoliasearch(functions.config().algolia.appid, functions.config().algolia.apikey)
const collectionIndexName = functions.config().projectId === 'PROJECT-XXXX' ? 'prod_SEARCH' : 'dev_SEARCH';
const collectionIndex = algoliaClient.initIndex(collectionIndexName);
//rename to uploadUsersToAlgolia
export const sendCollectionToAlgolia = functions.https.onRequest(async (req, res) => {
const algoliaRecords: any[] = [];
const querySnapshot = await db.collection('users').get();
querySnapshot.docs.forEach(doc => {
const document = doc.data();
const record = {
objectID: doc.id,
fullname: document.fullname,
bio: document.bio,
username: document.username,
uid: document.uid,
profileImageURL: document.profileImageURL,
backgroundImageURL: document.backgroundImageURL,
fcmToken: document.fcmToken,
accountCreated: document.accountCreated,
inspirationCount: document.inspriationCount,
BucketListCount: document.BucketListCount,
CompletedBucketListCount: document.CompletedBucketListCount,
FriendsCount: document.FriendsCount
};
algoliaRecords.push(record);
});
// After all records are created, we save them to
collectionIndex.saveObjects(algoliaRecords, (_error: any, content: any) => {
res.status(200).send("users collection was indexed to Algolia successfully.");
});
});
If you just want to change the default 1 minute timeout, you can do that when you configure the function.
functions.runWith({timeoutSeconds: X}).https.onRequest(async (req, res)
Increasing the timeout won't help if your function doesn't end up sending a response, so you should also add some logging/debugging to figure out if the final call to res.send() is actually happening. If the function never sends a response, it will definitely time out no matter what happens.

How can get email from current user logged in react-admin?

I am working in admin website using react-admin framework.
https://marmelab.com/react-admin/Readme.html
I need to show current user email that is logged. How can I get this functionality?
Regards
UPDATE:
There is a dedicated hook to retrieve this kind of data called useGetIdentity
ORIGINAL:
I have implemented a custom verb in the authProvier similarly to the Dwadelfri's answer. It gets pretty handy because you can access it through the built in hook useAuthProvider
inside authProvider.js
import decodeJwt from 'jwt-decode';
const getCurrentUser = () => {
// the place where you saved user's data on login
const user = JSON.parse(localStorage.getItem("user"));
const decodedToken = decodeJwt(user.token);
return {
...user,
...decodedToken,
};
}
export default {
login: loginHandler,
logout: logoutHandler,
checkAuth: checkAuthHandler,
checkError: checkErrorHandler,
getPermissions: getPermissionsHandler,
//custom verbs
signUp: signUpHandler,
getCurrentUser: getCurrentUser,
};
Then the code looks pretty neat when you decide to call it:
const authProvider = useAuthProvider();
const user = authProvider.getCurrentUser();
I only found this kinda hacky way, I'm looking for better alternative but for right now I'm using this to get the user id which could be used to get other stuff via the dataProvider.
import decodeJwt from 'jwt-decode';
const getUserId = () => {
return decodeJwt(localStorage.getItem("token")).sub;
}
this asumes you use jwt and your token includes the user id
const token = jwt.sign({ sub: user.id}, config.secret);
the solution that I got is the following:
Inside your Data page (posts.js for instance)
First import the following Firebase package
import firebase from 'firebase/app';
Then get the connected user straight from the firebase context as the following:
const email = firebase.auth().currentUser.email;
The filter part would be the following:
<List
{...props}
filter={{ createdby: email }}>```

Is NightmareJS (electron browser) compatible Firebase Functions?

I have an app that takes a New York Times recipe URL, and converts the list of ingredients into a shopping to-do list.
Because the New York Times uses React, none of the data is available via standard scraping - the index.html is mostly blank. I have to use a library like NightmareJS, which uses an Electron browser to fully construct the DOM (including the Javascript) so that I can then scrape that constructed-DOM for data.
But this doesn't seem to work. Here's the code I have included in my /functions/index.js file:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions')
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const Nightmare = require('nightmare')
const Actions = require('nightmare-react-utils').Actions
exports.listify = functions.https.onRequest((req, res) => {
console.log("YOU ARE NOW INSIDE THE LISTIFY FUNCTION!")
Nightmare.action(...Actions)
const nightmare = new Nightmare({ show: false })
const selector = 'ul.recipe-ingredients'
const queryUrl = req.query.url
nightmare
.goto(queryUrl)
.wait()
.evaluate((selector) => {
console.log("YOU ARE NOW INSIDE THE EVALUATE!")
const recipeIngredientsObject = document.querySelector(selector).children
const result = []
const ingredientKeys = Object.keys(recipeIngredientsObject)
ingredientKeys.forEach((key) => {
const ingredientObject = recipeIngredientsObject[key]
const quantityAndIngredient = ingredientObject.children
result.push({
"quantity": quantityAndIngredient[0].innerText,
"ingredient": quantityAndIngredient[1].innerText
})
})
return result
}, selector)
})
When I call this Function from my front-end, I see the first console log in my Firebase logs - "YOU ARE NOW INSIDE THE LISTIFY FUNCTION!" - but I do not see the second message: "YOU ARE NOW INSIDE THE EVALUATE!"
Can I not use NightmareJS with Firebase Functions?
The console.log message will never appear. When you run evaluate, that function is executed inside the context of the headless browser, so will not log to terminal.
Try something like...
.evaluate((selector) => {
return document.querySelector(selector)
}, selector)
.end()
.then(console.log)
To see if it's working at all.

Categories