<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ian de Jesus</title>
    <description>The latest articles on DEV Community by Ian de Jesus (@iandjx).</description>
    <link>https://dev.to/iandjx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F117754%2F1c74208f-8eea-4f18-b864-d2836adfcfd1.jpeg</url>
      <title>DEV Community: Ian de Jesus</title>
      <link>https://dev.to/iandjx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iandjx"/>
    <language>en</language>
    <item>
      <title>Wagmi Essentials</title>
      <dc:creator>Ian de Jesus</dc:creator>
      <pubDate>Sat, 24 Feb 2024 04:15:37 +0000</pubDate>
      <link>https://dev.to/iandjx/wagmi-essentials-bh0</link>
      <guid>https://dev.to/iandjx/wagmi-essentials-bh0</guid>
      <description>&lt;p&gt;Simulate contracts to get error messages before user tries it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data, error, status } = useSimulateContract({
    abi: BookingFactoryABI,
    address: process.env.NEXT_PUBLIC_BOOKING_FACTORY_ADDRESS as any,
    functionName: 'createBooking',
    args: [1n, 'simulate'],
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estimate gas price for transaction to check if user has enough balance&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  useEffect(() =&amp;gt; {
    const a = async () =&amp;gt; {
      if (publicClient) {
        const a = await estimateContractGas(publicClient, {
          abi: BookingFactoryABI,
          address: process.env.NEXT_PUBLIC_BOOKING_FACTORY_ADDRESS as any,
          functionName: 'createBooking',
          args: [1n, 'simulate'],
        })
        console.log(a, 'gasss')
      }
    }
    a()
  }, [publicClient])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch contract events to to retrieve write transaction reults&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  useEffect(() =&amp;gt; {
    if (publicClient) {
      publicClient.watchContractEvent({
        abi: BookingFactoryABI,
        eventName: 'BookingCreated',
        onLogs: (logs) =&amp;gt; {
          console.log(logs)
        },
      })
    }
  }, [publicClient])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait for transaction receipt after on success in writecontractasync to get events for that transaction&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await writeContractAsync(
      {
        abi: BookingFactoryABI,
        address: process.env.NEXT_PUBLIC_BOOKING_FACTORY_ADDRESS as any,
        functionName: 'createBooking',
        args: [influencersRequired, bookingId],
      },
      {
        onError: (error) =&amp;gt; {
          setIsLoading(false)
        },
        onSuccess: async (hash) =&amp;gt; {
          if (publicClient) {
            const receipt = await waitForTransactionReceipt(publicClient, {
              hash,
            })

            const bookingIdInBytes = keccak256(toBytes(bookingId))
            const log = receipt.logs.find((log) =&amp;gt; log.topics[1] === bookingIdInBytes)

            if (log) {
              await axios.post('/api/booking/set-blockchain-address', {
                booking_id: bookingId,
                blockchain_address: log.topics[0],
              })

              // window.open('/dashboard/my-bookings', '_self')
            }
          }

          setIsLoading(false)
        },
      },
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Running a subgraph locally</title>
      <dc:creator>Ian de Jesus</dc:creator>
      <pubDate>Wed, 19 Jul 2023 05:04:36 +0000</pubDate>
      <link>https://dev.to/iandjx/runing-a-subgraph-locally-357</link>
      <guid>https://dev.to/iandjx/runing-a-subgraph-locally-357</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'endraw'&lt;/p&gt;
</description>
      <category>blockchain</category>
    </item>
    <item>
      <title>NFT Games Like Diablo 3 Auction House</title>
      <dc:creator>Ian de Jesus</dc:creator>
      <pubDate>Fri, 14 Jan 2022 20:30:54 +0000</pubDate>
      <link>https://dev.to/iandjx/nft-games-like-diablo-3-auction-house-g4p</link>
      <guid>https://dev.to/iandjx/nft-games-like-diablo-3-auction-house-g4p</guid>
      <description>&lt;p&gt;Seriously. I was reading about NFT games and it feels like its only advantage is that you can buy stuff using real money (crypto) with/without having to transact within the game platform. Its like the Diablo 3 auction house on steroids. We know how this ends. Unless these NFT game developers make their games have this great game experience they would just end up closing their company.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PayPal Integration Using NextJS and Prisma</title>
      <dc:creator>Ian de Jesus</dc:creator>
      <pubDate>Mon, 19 Jul 2021 05:38:42 +0000</pubDate>
      <link>https://dev.to/iandjx/paypal-integration-using-nextjs-and-prisma-21i8</link>
      <guid>https://dev.to/iandjx/paypal-integration-using-nextjs-and-prisma-21i8</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/iandjx/nextjs-paypal"&gt;Github Repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/kYGJxJIKC91bVQ336N/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/kYGJxJIKC91bVQ336N/giphy.gif" alt="Project Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial explains how to use NextJS as the backend to create and capture PayPal orders and store the order data in SQLite using Prisma. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the user clicks the PayPal button, we make a post request to &lt;code&gt;/paypal/createOrder&lt;/code&gt; to create a new Paypal Order. The OrderID and a status of PENDING is stored in SQLite through Prisma&lt;/li&gt;
&lt;li&gt;After the user pays for the order, we make a post request to &lt;code&gt;paypal\captureOrder&lt;/code&gt; to capture the payment and then update the status to PAID.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Initial Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpx create-next-app --typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install all required libraries&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm i @paypal/checkout-server-sdk prisma @prisma/client prisma @paypal/react-paypal-js axios react-query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;baseUrl: "./"&lt;/code&gt; in &lt;code&gt;tsconfig.json&lt;/code&gt; to make imports easy to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Prisma
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;prisma/schema.prisma&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
        provider = "prisma-client-js"
}

datasource db {
        provider = "sqlite"
        url      = "file:./dev.db"
}


model Payment {
        id      Int    @id @default(autoincrement())
        orderID String
        status  String
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep it simple we will only be storing the PayPal OrderID and its status&lt;/p&gt;

&lt;p&gt;Lets migrate and generate our Prisma client&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm prisma migrate dev
pnpm prisma generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;lib/prisma.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {PrismaClient} from '@prisma/client'

// Prevent multiple instances of Prisma Client in development
declare const global: typeof globalThis &amp;amp; {prisma?: PrismaClient}

const prisma = global.prisma || new PrismaClient()
if (process.env.NODE_ENV === 'development') global.prisma = prisma

export default prisma

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup Paypal
&lt;/h2&gt;

&lt;p&gt;Create an &lt;code&gt;.env&lt;/code&gt; file and add your PayPal Client and Secret&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=
PAYPAL_CLIENT_ID=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;lib/paypal.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import checkoutNodeJssdk from '@paypal/checkout-server-sdk'

const configureEnvironment = function () {
  const clientId = process.env.PAYPAL_CLIENT_ID
  const clientSecret = process.env.PAYPAL_CLIENT_SECRET

  return process.env.NODE_ENV === 'production'
    ? new checkoutNodeJssdk.core.LiveEnvironment(clientId, clientSecret)
    : new checkoutNodeJssdk.core.SandboxEnvironment(clientId, clientSecret)
}

const client = function () {
  return new checkoutNodeJssdk.core.PayPalHttpClient(configureEnvironment())
}

export default client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the client to create and capture orders.&lt;/p&gt;

&lt;p&gt;Let us now create our 2 API endpoints.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;/api/paypal/createOrder.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import prisma from 'lib/prisma'
import type { NextApiRequest, NextApiResponse } from 'next'
import client from 'lib/paypal'
import paypal from '@paypal/checkout-server-sdk'

export default async function handle(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const PaypalClient = client()
  //This code is lifted from https://github.com/paypal/Checkout-NodeJS-SDK
  const request = new paypal.orders.OrdersCreateRequest()
  request.headers['prefer'] = 'return=representation'
  request.requestBody({
    intent: 'CAPTURE',
    purchase_units: [
      {
        amount: {
          currency_code: 'PHP',
          value: '100.00',
        },
      },
    ],
  })
  const response = await PaypalClient.execute(request)
  if (response.statusCode !== 201) {
    res.status(500)
  }

  //Once order is created store the data using Prisma
  await prisma.payment.create({
    data: {
      orderID: response.result.id,
      status: 'PENDING',
    },
  })
  res.json({ orderID: response.result.id })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;api/paypal/captureOrder.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { NextApiRequest, NextApiResponse } from 'next'
import client from 'lib/paypal'
import paypal from '@paypal/checkout-server-sdk'
import prisma from 'lib/prisma'

export default async function handle(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  //Capture order to complete payment
  const { orderID } = req.body
  const PaypalClient = client()
  const request = new paypal.orders.OrdersCaptureRequest(orderID)
  request.requestBody({})
  const response = await PaypalClient.execute(request)
  if (!response) {
    res.status(500)
  }

  // Update payment to PAID status once completed
  await prisma.payment.updateMany({
    where: {
      orderID,
    },
    data: {
      status: 'PAID',
    },
  })
  res.json({ ...response.result })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup FrontEnd
&lt;/h2&gt;

&lt;p&gt;Update &lt;code&gt;_app.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import '../styles/globals.css'
import type {AppProps} from 'next/app'
import {QueryClient, QueryClientProvider} from 'react-query'

const queryClient = new QueryClient()

function MyApp({Component, pageProps}: AppProps) {
  return (
    &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
  )
}
export default MyApp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;react-query&lt;/code&gt; for ease of making async calls&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;index.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios, { AxiosError } from 'axios'
import Head from 'next/head'
import Image from 'next/image'
import { useMutation } from 'react-query'
import styles from '../styles/Home.module.css'
import {
  PayPalScriptProvider,
  PayPalButtons,
  FUNDING,
} from '@paypal/react-paypal-js'

export default function Home() {
  const createMutation = useMutation&amp;lt;{ data: any }, AxiosError, any, Response&amp;gt;(
    (): any =&amp;gt; axios.post('/api/paypal/createOrder'),
  )
  const captureMutation = useMutation&amp;lt;string, AxiosError, any, Response&amp;gt;(
    (data): any =&amp;gt; axios.post('/api/paypal/captureOrder', data),
  )
  const createPayPalOrder = async (): Promise&amp;lt;string&amp;gt; =&amp;gt; {
    const response = await createMutation.mutateAsync({})
    return response.data.orderID
  }

  const onApprove = async (data: OnApproveData): Promise&amp;lt;void&amp;gt; =&amp;gt; {
    return captureMutation.mutate({ orderID: data.orderID })
  }
  return (
    &amp;lt;div className={styles.container}&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;Create Next App&amp;lt;/title&amp;gt;
        &amp;lt;meta name="description" content="Generated by create next app" /&amp;gt;
        &amp;lt;link rel="icon" href="/favicon.ico" /&amp;gt;
      &amp;lt;/Head&amp;gt;
      &amp;lt;main className={styles.main}&amp;gt;
        {captureMutation.data &amp;amp;&amp;amp; (
          &amp;lt;div&amp;gt;{JSON.stringify(captureMutation.data)}&amp;lt;/div&amp;gt;
        )}
        &amp;lt;PayPalScriptProvider
          options={{
            'client-id': process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID as string,
            currency: 'PHP',
          }}
        &amp;gt;
          &amp;lt;PayPalButtons
            style={{
              color: 'gold',
              shape: 'rect',
              label: 'pay',
              height: 50,
            }}
            fundingSource={FUNDING.PAYPAL}
            createOrder={createPayPalOrder}
            onApprove={onApprove}
          /&amp;gt;
        &amp;lt;/PayPalScriptProvider&amp;gt;
      &amp;lt;/main&amp;gt;

      &amp;lt;footer className={styles.footer}&amp;gt;
        &amp;lt;a
          href="https://vercel.com?utm_source=create-next-app&amp;amp;utm_medium=default-template&amp;amp;utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        &amp;gt;
          Powered by{' '}
          &amp;lt;span className={styles.logo}&amp;gt;
            &amp;lt;Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} /&amp;gt;
          &amp;lt;/span&amp;gt;
        &amp;lt;/a&amp;gt;
      &amp;lt;/footer&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

declare global {
  interface Window {
    paypal: any
  }
}

interface OnApproveData {
  billingToken?: string | null
  facilitatorAccessToken: string
  orderID: string
  payerID?: string | null
  paymentID?: string | null
  subscriptionID?: string | null
  authCode?: string | null
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We declare &lt;code&gt;createPaypalOrder&lt;/code&gt; and &lt;code&gt;onApprove&lt;/code&gt; functions. Both functions are passed as props to the PayPal Button. &lt;code&gt;createPaypalOrder&lt;/code&gt; is initially called on click of the PayPal button which triggers creation of the PayPal Order. The mutation returns the orderID that will be consumed by the onApprove function to capture the payment. After successful payment, the result is JSON stringified and displayed in the browser.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>prisma</category>
      <category>paypal</category>
    </item>
  </channel>
</rss>
