DEV Community

Mark Okhman
Mark Okhman

Posted on • Edited on

3

Using DeLab Connect with Next.js

Recently I've seen a release of an awesome repository enabling single-page React apps to seamlessly integrate authentication with a number of TON wallets.

Kudos to DeLab team ❤️
https://github.com/delab-team/connect

I plan to record a video soon where I will go into more detail on when this is a good lib to use and when we should go with the standard "per-wallet" authentication approach. Subscribe to my Telegram channel if you don't want to miss it https://t.me/markokhmandev

Because I'm using Next.js for most of my web projects, I've run into some issues using DeLab Connect. However, a single React hook solves those issues. This hook makes sure that we are importing the DeLab Connect only on the client side. Furthermore, our hook has an interface (connectInfo and callbacks) to interact with the DeLab Connect instance.

Before we get to the hook's code, let's do some preparation. You will need to prepare the delab's module before passing it to Next.js. For this you need two things:

  • Install next-transpile-modules:
yarn add next-transpile-modules
Enter fullscreen mode Exit fullscreen mode
  • Replace default next.config.js with following code:
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
};
const withTM = require("next-transpile-modules")(["@delab-team/connect"]); // pass the modules you would like to see transpiled
module.exports = withTM(nextConfig);
Enter fullscreen mode Exit fullscreen mode

Now we are good to go with the Hook's code:

import { DeLabEvent, DeLabNetwork } from "@delab-team/connect";
import { createElement, useEffect, useState } from "react";
export const useDeLabConnect = (props: {
connectInfo: {
url: string;
name: string;
network: DeLabNetwork;
};
callbacks: {
onConnect?: (event: DeLabEvent) => void;
onDisconnect?: () => void;
onApproveLink?: (event: DeLabEvent) => void;
onError?: (event: DeLabEvent) => void;
onErrorTransaction?: (event: DeLabEvent) => void;
onErrorTonCoinWallet?: (event: DeLabEvent) => void;
onErrorTonhub?: (event: DeLabEvent) => void;
onErrorTonkeeper?: (event: DeLabEvent) => void;
};
}) => {
const [DeLabConnector, setDeLabConnector] = useState<any>();
const [DeLabModal, setDeLabModal] = useState<any>(null);
const [DeLabButton, setDeLabButton] = useState<any>(null);
useEffect(() => {
(async () => {
if (typeof window !== "undefined") {
const DeLab = await import("@delab-team/connect");
const DeLabConnector = new DeLab.DeLabConnect(
props.connectInfo.url,
props.connectInfo.name,
props.connectInfo.network
);
setDeLabConnector(DeLabConnector);
setDeLabModal(
createElement(DeLab.DeLabModal, {
DeLabConnectObject: DeLabConnector,
scheme: "dark",
})
);
setDeLabButton(
createElement(DeLab.DeLabButton, {
DeLabConnectObject: DeLabConnector,
scheme: "dark",
})
);
DeLabConnector.on("connect", async (event: DeLabEvent) =>
props.callbacks.onConnect?.(event)
);
DeLabConnector.on("disconnect", () => {
props.callbacks.onDisconnect?.();
});
DeLabConnector.on("approve-link", (event: DeLabEvent) => {
props.callbacks.onApproveLink?.(event);
});
DeLabConnector.on("error", (event: DeLabEvent) => {
props.callbacks.onError?.(event);
});
DeLabConnector.on("error-transaction", (event: DeLabEvent) => {
props.callbacks.onErrorTransaction?.(event);
});
DeLabConnector.on("error-toncoinwallet", (event: DeLabEvent) => {
props.callbacks.onErrorTonCoinWallet?.(event);
});
DeLabConnector.on("error-tonhub", (event: DeLabEvent) => {
props.callbacks.onErrorTonhub?.(event);
});
DeLabConnector.on("error-tonkeeper", (event: DeLabEvent) => {
props.callbacks.onErrorTonkeeper?.(event);
});
DeLabConnector.loadWallet();
}
})();
}, []);
return { DeLabConnector, DeLabModal, DeLabButton };
};

You can place this hook anywhere in your project (ex. /shared/hooks/useDeLabConnect.ts) and then import it on your page.

How do we use it?

Inside of our page component we are placing the use of our hook:

 const { DeLabConnector, DeLabModal, DeLabButton } = useDeLab({
    connectInfo: {
      url: "https://example.com",
      name: "Example",
      network: "testnet",
    },
    callbacks: {
      onConnect: async (event: DeLabEvent) => handleConnect(event),
      onDisconnect: () => {
        console.log("disconect");
      },
      onErrorTransaction: (event: DeLabEvent) => handleErrorTransaction(event),
      // ... other callbacks handled in our hook
    },
  });
Enter fullscreen mode Exit fullscreen mode

Our hook returns 3 important instances:
DeLabConnector - of type DeLabConnect, we will use this one to request transactions etc.
DeLabModal & DeLabButton - Elements, we will simply put them on the page

Here is a full example of our Next.js page using the useDeLabConnect.ts

import {
DeLabConnecting,
DeLabEvent,
DeLabTransaction,
} from "@delab-team/connect";
import { useState } from "react";
import { useDeLab } from "../shared/DeLabHook";
export default function Home() {
const [isConnected, setIsConnected] = useState(false);
const [connectConfig, setConnectConfig] = useState<DeLabConnecting>();
const { DeLabConnector, DeLabModal, DeLabButton } = useDeLab({
connectInfo: {
url: "https://example.com",
name: "Example",
network: "testnet",
},
callbacks: {
onConnect: async (event: DeLabEvent) => handleConnect(event),
onDisconnect: () => {
console.log("disconect");
},
onErrorTransaction: (event: DeLabEvent) => handleErrorTransaction(event),
// ... other callbacks handled in our hook
},
});
const handleConnect = async (event: DeLabEvent) => {
setIsConnected(true);
setConnectConfig(event.data);
};
const handleErrorTransaction = async (event: DeLabEvent) => {
console.log("error transaction", event.data);
};
const triggerDisconnect = async () => {
await DeLabConnector!.disconnect();
setIsConnected(false);
};
const triggerRequestTransaction = async () => {
const trans: DeLabTransaction = {
to: "EQCkR1cGmnsE45N4K0otPl5EnxnRakmGqeJUNua5fkWhales",
value: "1000000", // string value in nano-coins
};
const data = await DeLabConnector!.sendTransaction(trans);
if (connectConfig!.typeConnect === "tonkeeper") {
// display qrcode code ...
console.log("tonkeeper link: ", data);
}
};
return (
<div>
{DeLabModal}
{isConnected ? (
<>
<p>Connected</p>
<button onClick={triggerDisconnect}>Disconnect</button>
<button onClick={triggerRequestTransaction}>
Request transaction
</button>
</>
) : (
DeLabButton
)}
</div>
);
}
view raw Home.tsx hosted with ❤ by GitHub

That's it :) Let me know in comments, what you think about this.
And bro, please subscribe to my Telegram channel: https://t.me/markokhmandev

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay