2023.11.06 트랜잭션 리스트 component

이무헌·2023년 11월 6일
0

block explore

목록 보기
2/6

1.txListContainer


/* eslint-disable @next/next/no-img-element */
"use client";
import React, { useEffect, useState } from "react";
import Image from "next/image";
import { IAddInfo, TxListProps } from "./ineterface";
import { createPortal } from "react-dom";
import AdditionalInfo from "./additionalInfo";
import { Popover } from "@headlessui/react";
import TxList from "./txList";

const TxListWrap: React.FC<TxListProps> = ({ txList }) => {
  const [addInfoModal, setAddInfoModal] = useState<Element | null>(null);
  const [isToggled, setIsToggled] = useState<boolean>(false);
  useEffect(() => {
    setAddInfoModal(document.getElementById("portal"));
  }, [isToggled]);

  // 실제에서는 react-query로 가져올 예정
  const [addInfoTempData, setAddInfoTempData] = useState<IAddInfo>({
    status: "Success",
    transactionFee: "0.0000000000231",
    gasInfo: "293840",
    gasLimit: "318840",
    nonce: "0",
    blockNum: "18497",
    position: "18",
  });

  const toggleHandler = () => {
    setIsToggled(!isToggled);
  };

  return (
    <div className="overflow-x-auto overflow-y-scroll max-h-[600px]">
      <div className="w-[300%] h-8 border-b flex ">
        <div className="w-[5%] flex justify-center items-center ">?</div>
        <div className=" w-[20%] flex justify-center items-center  ">
          Txn Hash
        </div>
        <div className=" w-[10%] flex justify-center items-center  ">
          Method
        </div>
        <div className=" w-[10%] flex justify-center items-center  ">Block</div>
        <div className=" w-[10%] flex justify-center items-center  ">Age</div>
        <div className=" w-[20%] flex justify-center items-center  ">From</div>
        <div className=" w-[20%] flex justify-center items-center  ">To</div>
        <div className=" w-[10%] flex justify-center items-center  ">Value</div>
      </div>
      <TxList txList={txList} toggleHandler={toggleHandler} />

      {isToggled && addInfoModal
        ? createPortal(
            <AdditionalInfo
              addInfoTempData={addInfoTempData}
              toggleHandler={toggleHandler}
            />,
            addInfoModal
          )
        : ""}
      {/* <div className="w-full min-h-[300px] h-fit m-auto border-y-2 border-gray-400">
        {txList.map((el, index) => {
          return (
            <div className="" key={index}>
              <div className="h-0.5 bg-gray-300 w-full m-auto mt-3"></div>
            </div>
          );
        })}
      </div> */}
    </div>
  );
};

export default TxListWrap;
  • 트랜잭션 리스트들을 보여주는 가장 상위 컴포넌트다.
  {isToggled && addInfoModal
        ? createPortal(
            <AdditionalInfo
              addInfoTempData={addInfoTempData}
              toggleHandler={toggleHandler}
            />,
            addInfoModal
          )
        : ""}
        
  • txList에 대한 and연산자는 props로 넘겨주었다. (type을 null값이 허용되도록 하였다.)
  • 위 코드는 next에서 지원하는 포탈 함수로 modal을 띄어줄 때 유용하다. 반드시 layout(루트)에 다음과 같은 태그가 추가되어야 한다.
 <html lang="en">
      <Header />
      <body className={inter.className}>
        {children}
        //이 부분
        <div className="relative" id="portal"></div>
      </body>
      <Footer />
    </html>

2.트랜잭션 리스트를 반환하는 txList component


/* eslint-disable @next/next/no-img-element */
import React from "react";
import { TxListWrapProps } from "./ineterface";
import TxItem from "./txItem";

const TxList: React.FC<TxListWrapProps> = ({ txList, toggleHandler }) => {
  return (
    <div>
      {txList &&
        txList.map((ele) => (
          <TxItem TxItem={ele} toggleHandler={toggleHandler} key={ele.txHash} />
        ))}
    </div>
  );
};

export default TxList;
  • key값은 고유값인 tx값으로 주었다.

3. 트랜잭션 하나의 row인 txItem

/* eslint-disable @next/next/no-img-element */
import React from "react";
import { TxItemProps } from "./ineterface";

const TxItem: React.FC<TxItemProps> = ({ TxItem, toggleHandler }) => {
  return (
    <div className="w-[300%] h-14 border-b flex relative ">
      <div className="w-[5%] flex  items-center justify-center p-2 relative">
        <div className="relative">
          <img
            src="https://i.pinimg.com/originals/ce/9c/4e/ce9c4e4f06e724a10b3766845f93a051.png"
            alt="detail"
            className="w-5 h-5 cursor-pointer "
            onClick={toggleHandler}
          />
        </div>
      </div>

      <div
        className=" w-[20%]   truncate  p-2"
        style={{
          lineHeight: "2.3rem",
        }}
      >
        {TxItem.txHash}
      </div>
      <div className=" w-[10%] flex justify-center items-center  p-2 ">
        {TxItem.method}
      </div>
      <div className=" w-[10%] flex justify-center items-center  p-2  ">
        {TxItem.block}
      </div>
      <div className=" w-[10%] flex justify-center items-center p-2  ">
        {TxItem.age}
      </div>
      <div
        className=" w-[20%]   truncate p-2"
        style={{
          lineHeight: "2.3rem",
        }}
      >
        {TxItem.from}
      </div>
      <div
        className=" w-[20%]   truncate p-2"
        style={{
          lineHeight: "2.3rem",
        }}
      >
        {TxItem.to}
      </div>
      <div className=" w-[10%] flex justify-center items-center p-2  ">
        {TxItem.value}
      </div>
    </div>
  );
};

export default TxItem;

4.interface를 모아놓은 interface.d.ts

// interface ItxList {
//     txHash: string;
//     method: string;
//     block: string;
//     from: string;
//     to: string;
//     value: string;
//     age: string;
//   }
export interface ItxList {
  txHash: string;
  method: string;
  block: string;
  from: string;
  to: string;
  value: string;
  age: string;
}

export interface TxListProps {
  txList: ItxList[];
}

export interface TxListWrapProps {
  txList: ItxList[] | null;
  toggleHandler: () => void;
}

export interface TxItemProps {
  TxItem: ItxList;
  toggleHandler: () => void;
}

export interface IAddInfo {
  status: string;
  transactionFee: string;
  gasInfo: string;
  nonce: string;
  gasLimit: string;
  blockNum: string;
  position: string;
}

export interface IAdditionalInfoProps {
  addInfoTempData: IAddInfo;
  toggleHandler: () => void;
}

5.모달창

/* eslint-disable @next/next/no-img-element */
import React from "react";
import { IAdditionalInfoProps } from "./ineterface";

const AdditionalInfo: React.FC<IAdditionalInfoProps> = ({
  addInfoTempData,
  toggleHandler,
}) => {
  return (
    <div className=" fixed top-0 left-0 z-30 w-screen h-screen bg-modalBackgroundColor flex justify-center items-center  ">
      <div className="z-40 border-2 border-black w-80 h-96 rounded-lg p-4 bg-white overflow-scroll absolute top-[40%] left-[50%] -translate-x-1/2 -translate-y-1/2">
        <div className="flex w-full justify-between items-center h-1/6">
          <div className="text-lg font-bold">Additional Info</div>
          <img
            width={20}
            height={20}
            src="https://png.pngtree.com/png-vector/20190411/ourmid/pngtree-vector-cross-icon-png-image_925896.jpg"
            alt="x이미지"
            onClick={toggleHandler}
          />
        </div>
        <div className="flex flex-col w-full text-sm h-1/5 border-b justify-center">
          <div className="">Status:</div>
          <div className="flex w-full justify-between">
            <span>{addInfoTempData.status}</span>
            <span>{addInfoTempData.blockNum} Block Confirmation</span>
          </div>
        </div>
        <div className="flex flex-col w-full text-sm h-1/5 border-b justify-center">
          <div className="">TransactionFee:</div>
          <div className="flex w-full justify-between">
            <span>{addInfoTempData.transactionFee}ETH</span>
            <span>$0.00</span>
          </div>
        </div>
        <div className="flex flex-col w-full text-sm h-1/5 border-b justify-center">
          <div className="">Gas Info:</div>
          <div className=" w-full text-xs">
            <div>
              {addInfoTempData.gasInfo} gas used from {addInfoTempData.gasLimit}{" "}
              limit
            </div>
            <div>@0.0000000000000000004843ETH(0.000004834Gwei)</div>
          </div>
        </div>
        <div className="flex flex-col w-full text-sm h-1/5 border-b justify-center">
          <div className="">Nonce:</div>
          <div className="flex w-full justify-between">
            <span>{addInfoTempData.nonce}</span>
            <span>(in the position {addInfoTempData.position})</span>
          </div>
        </div>
      </div>
    </div>
  );
};

export default AdditionalInfo;

6.실행화면

7.피드백

폴더구조!!! 폴더구조를 이음새 있고 직관적으로 구성하여 다른 사람으로 하여금 편하게 볼 수 있도록 하여야 한다. page,layout,content,component로 나누어 재사용성을 높이고 직관성을 높일 수 있게 만들어야 겠다.

profile
개발당시에 직면한 이슈를 정리하는 곳

0개의 댓글