Building Ecommerce Applications with Next.js
Jun 11, 2024

Next.js can be a great platform for building ecommerce applications but implementations can often gravitate towards the overly complex. But it does not have to be that way when deployed with Perspect. Follow along to see how we support Next.js.

Install Next.js and modify your next.config.mjs with this content:   

/** @type {import('next').NextConfig} */
const nextConfig = { 
  output: 'export', 
  trailingSlash: true 
};

export default nextConfig;

  In your pages directory, create a file called products.jsx with a getStaticProps() function that looks like this:   

import fs from 'fs';
import path from 'path';

export async function getStaticProps() {
  // Path to the posts.json file
  const filePath = path.join(process.cwd(), 'perspect.product_categories.json');

  // Read the file
  const jsonData = await fs.promises.readFile(filePath, 'utf8');

  // Parse the JSON data
  const product_categories = JSON.parse(jsonData);

  return {
    props: {
      product_categories,
    },
  };
}
 
export default function Products({ product_categories }) {
  return (
    <div>
      <h1>Product Categories</h1>
      <pre>{JSON.stringify(product_categories, null, 2)}</pre>
    </div>
  );
}

   That will read the perspect.product_categories file that Perspect places into the root directory during the build process. perspect.product_categories will contain a list of all product categories which contains a list of respective products, media, etc.    Build out the product pages using these properties as you see fit. You can then initiate a checkout session by sending a POST request to /checkout (or to whatever path where you've configured the checkout function) using a JS function such as this:    Here's the JavaScript code block for the handleCheckout function in Markdown format:  

import { loadStripe } from '@stripe/stripe-js';
import { useState } from 'react';

const handleCheckout = async (event) => {
  if (totalCount === 0) {
    return;
  }

  setProcessing(true);
  let sk = '';
  let perspect = window.perspect;
  
  if (perspect.site_env === 'live') {
    sk = perspect.spkl;
  } else {
    sk = perspect.spkt;
  }
  
  let said = perspect.said;
  var stripe = await loadStripe(sk, {
    stripeAccount: said,
  });

  // First, make a GET request to obtain the CSRF token
  try {
    const csrfResponse = await fetch('/csrf');
    const csrfData = await csrfResponse.json();
    const csrfToken = csrfData.csrf_token;

    // Prepare headers to indicate JSON content type and to send the CSRF token as a cookie
    const headers = new Headers({
      "Content-Type": "application/json",
      "Cookie": `csrf_token=${csrfToken}`,
    });

    // Create an array to hold your cart items in JSON format
    let cartItemsJson = cartItems.map(item => ({
      stripe_product_id: item.stripe_product_id_test,
      quantity: item.count,
    }));

    // Perform the fetch request to /checkout with JSON body including the CSRF token
    const checkoutResponse = await fetch('/checkout', {
      method: 'POST',
      headers: headers,
      body: JSON.stringify({ products: cartItemsJson, csrf_token: csrfToken }), // Stringify the array of cart items and include CSRF token
    });

    const session = await checkoutResponse.json();
    await stripe.redirectToCheckout({ sessionId: session.id });

  } catch (error) {
    console.error('Error:', error);
  } finally {
    setProcessing(false); // Ensure processing is set to false in the end
  }
};

export default handleCheckout;

  This function handles the checkout process, including fetching a CSRF token, preparing headers, sending cart items to the server, and redirecting to Stripe's checkout page.