1

I'm making payment function for my static e-commerce Next.js app.

For payment I've several stages:

  1. Making cart page with shipping information form and button "Pay" which redirect to /payment page;
  2. On /payment page I connect with my payment service and need to get cart info from Context API, but I can't use Context API in getStaticProps it's my problem. Payment page needs just get cart data and redirects on external service payment form.

Code for page /payment is below:

import { useEffect, useContext } from "react"
import QiwiBillPaymentsAPI from "@qiwi/bill-payments-node-js-sdk"

import { CartContext } from "@/context/GlobalState"

export default function Payment ({ payUrl }) {
    useEffect(() => window.location.assign(payUrl))
    return (
        <span>Redirect</span>
    )
}


export async function getStaticProps() {
    const qiwiApi = new QiwiBillPaymentsAPI(process.env.QIWI_SECRET_KEY)

    const { state, dispatch } = useContext(CartContext)
    const { cart } = state

    const billId = qiwiApi.generateId()
    const lifetime = qiwiApi.getLifetimeByDay(1);
    const fields = {
        amount: 1.00,
        currency: "RUB",
        expirationDateTime: lifetime,
    }

    const payment_data = await qiwiApi.createBill( billId, fields )
    const payUrl = payment_data.payUrl

    return { props: { payUrl }}
}

Please, help me with any ideas.

7
  • 2
    getStaticProps runs at build-time on the server. You won't have access to any runtime or client-side logic in there. Also, why do you need access to the context if you don't seem to be using the cart data in getStaticProps? Couldn't you handle the context in your Payment component instead? Commented Mar 13, 2021 at 18:26
  • Just one thing I had noticed from your code, you are using window.location.assign, which is probably a good idea in this case. But I'm afraid of you are using the same thing for everything. Make sure you use next router. Otherwise you are completely opt yourself out from SPA and advantage of using Next.js Commented Mar 13, 2021 at 19:16
  • @Yunhai Thanks for your attention! Yes, I'm using window.location.assign only in this case. And I was looking for approach to make it with next router, but I can't. If you know, tell me please! Commented Mar 13, 2021 at 20:15
  • @juliomalves I need to have context api access in getStaticProps for change amount (total price for future payment) in fields object and something more. For some reason I cannot use qiwiApi inside of the Payment component, I tried it in useEffect or just in function but in don't work and returns error with 'fs'. Commented Mar 13, 2021 at 20:21
  • 3
    I'd recommend you move the getStaticProps code to an API route, then make a request from your Payment component to that API route with whatever you need from the context. Commented Mar 13, 2021 at 20:41

1 Answer 1

2

Possible solution!

I've made API Route with code from my getStaticProps function (it gets total price and make query to payment service, then it return payment url). Code of api route is below:

import QiwiBillPaymentsAPI from "@qiwi/bill-payments-node-js-sdk"

export default async function handler(req, res) {
    const { 
        query: { total },
    } = req

    const qiwiApi = new QiwiBillPaymentsAPI(process.env.QIWI_SECRET_KEY)
    const billId = qiwiApi.generateId()
    const lifetime = qiwiApi.getLifetimeByDay(1);
    const fields = {
        amount: total,
        currency: "RUB",
        expirationDateTime: lifetime,
    }

    const payment_data = await qiwiApi.createBill( billId, fields )
    const payUrl = payment_data.payUrl

    res.json({ url: payUrl })
}

Then /payment page code (do query to my API route and get payment url, then redirect to payment form):

export default function Payment () {
    const { state, dispatch } = useContext(CartContext)
    const { cart } = state

    const fetcher = (...args) => fetch(...args).then(res => res.json())

    const { data, error } = useSWR(`/api/qiwi-pay?total=${cart.total}`, fetcher)

    if (error) return <div>failed to load</div>
    if (!data) return <div>loading...</div>

    window.location.assign(data.url)

    return (
        <>
            <span>Redirect to payment form.</span>
        </>
    )
}

This approach works very well!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.