[React] NFC 감지 기능 만들기

공이·2023년 10월 27일
0

React

목록 보기
4/4
post-thumbnail

이 글에서 NFC를 탭하면 블록체인 지갑을 만들어주는 기능에 대해 글을 썼었다.

그런데 useWalletAuth라는 지갑 생성 hook에 지갑 생성 기능 외에도 NFC를 감지하는 기능도 들어있어 단일책임원칙(SRP)을 위반하는 것 같아 리팩토링을 진행했다.

NFC 기능은 useNfc라는 hook으로 빼고
매개변수에 nfc가 감지된 후에 실행할 함수를 넣도록 했다.

import { useState } from "react";

export const useNfc = (nextFunction: () => Promise<void>) => {
  const [nfc, setNfc] = useState<any>(null);
  const [nfcSerialNumber, setNfcSerialNumber] = useState<string | null>(null);
  const [isNfcConnecting, setIsNfcConnecting] = useState(false);

  async function handleNfcReading() {
    if (typeof NDEFReader === "undefined") {
      console.log("NFC is not supported in this browser.");
      return;
    }

    try {
      console.log("NFC Reading Start");
      const ndef = new NDEFReader();
      setNfc(ndef);

      await ndef.scan();

      setIsNfcConnecting(true);

      ndef.addEventListener("readingerror", () => {
        console.log("Argh! Cannot read data from the NFC tag. Try another one?");
        setIsNfcConnecting(false);
      });

      ndef.addEventListener("reading", (event: any) => {
        const { message, serialNumber } = event;

        // setNfcMessage(message);
        setNfcSerialNumber(serialNumber);
        setIsNfcConnecting(false);
        nextFunction();
      });
    } catch (e) {
      console.log((e as Error).message);
    }
  }

  return {
    nfc,
    nfcSerialNumber,
    isNfcConnecting,
    handleNfcReading,
  };
};

아래처럼 useNfc hook을 이용한다.

"use client";

import {
  ComethProvider,
  ComethWallet,
  ConnectAdaptor,
  SupportedNetworks,
} from "@cometh/connect-sdk";
import { useState } from "react";
import { useWalletContext } from "./useWalletContext";
import { useNfc } from "./useNfc";
import { ethers } from "ethers";
import { COUNTER_ABI } from "@/abi/counter";
import { TOKEN_ABI } from "@/abi/sample-token";

export function useWalletAuth() {
  const { isNfcConnecting, nfcSerialNumber, handleNfcReading } = useNfc(connect);
  const { wallet, setWallet, setProvider, contract, setContract } = useWalletContext();
  const [isConnecting, setIsConnecting] = useState(false);
  const [isConnected, setIsConnected] = useState(false);
  const [connectionError, setConnectionError] = useState<string | null>(null);

  const apiKey = process.env.NEXT_PUBLIC_COMETH_API_KEY;
  const COUNTER_CONTRACT_ADDRESS = "0x3633A1bE570fBD902D10aC6ADd65BB11FC914624";
  const MATIC_ADDRESS = "0x0000000000000000000000000000000000001010";

  function displayError(message: string) {
    setConnectionError(message);
  }

  async function connect() {
    if (!apiKey) throw new Error("no apiKey provided");

    try {
      const walletAdaptor = new ConnectAdaptor({
        chainId: SupportedNetworks.MUMBAI,
        apiKey,
      });

      const instance = new ComethWallet({
        authAdapter: walletAdaptor,
        apiKey,
      });

      const localStorageAddress = window.localStorage.getItem("walletAddress");

      if (localStorageAddress) {
        const parsedLocalStorageAddress = JSON.parse(localStorageAddress);
        if (parsedLocalStorageAddress[nfcSerialNumber!]) {
          // if it is in localStorage, connect to it
          await instance.connect(parsedLocalStorageAddress[nfcSerialNumber!]);
        } else {
          // if it is not in localStorage, connect to it and save it to localStorage
          await instance.connect();
          const walletAddress = await instance.getAddress();
          parsedLocalStorageAddress[nfcSerialNumber!] = walletAddress;
          window.localStorage.setItem("walletAddress", JSON.stringify(parsedLocalStorageAddress));
        }
      } else {
        // if there is no localStorage, connect to it and save it to localStorage
        await instance.connect();
        const walletAddress = await instance.getAddress();
        const addressObject = { [nfcSerialNumber!]: walletAddress };
        window.localStorage.setItem("walletAddress", JSON.stringify(addressObject));
      }

      const instanceProvider = new ComethProvider(instance);

      // const contract = new ethers.Contract(MATIC_ADDRESS, TOKEN_ABI, instanceProvider.getSigner());

      const contract = new ethers.Contract(
        COUNTER_CONTRACT_ADDRESS,
        COUNTER_ABI,
        instanceProvider.getSigner()
      );

      setContract(contract);

      setIsConnected(true);
      setWallet(instance as any);
      setProvider(instanceProvider as any);
    } catch (e) {
      displayError((e as Error).message);
    } finally {
      setIsConnecting(false);
    }
  }

  async function disconnect() {
    if (wallet) {
      try {
        await wallet!.logout();
        setIsConnected(false);
        setWallet(null);
        setProvider(null);
        // setContract(null);
      } catch (e) {
        displayError((e as Error).message);
      }
    }
  }

  return {
    wallet,
    connect,
    disconnect,
    isConnected,
    isConnecting,
    isNfcConnecting,
    nfcSerialNumber,
    handleNfcReading,
    connectionError,
    setConnectionError,
    contract,
    setContract,
  };
}

0개의 댓글