개발 기록/도서관 관리 시스템

[Library Management System] 25.10.30 | (구현) 마이페이지 도서 대출 전체 조회(페이징 처리)

dev.jelee 2025. 10. 31. 00:11

[ 작업한 내용 ]

# Frontend

1. 도서 대출 전체 조회 기능 구현

- 마이페이지에서 대출 내역 탭 메뉴를 클릭하면 해당 페이지로 이동하고 도서 대출 전체 목록이 화면에 출력된다. 이때 출력되는 데이터의 개수는 1페이지 당 5개의 데이터가 출력 된다.

- 도서 전체 조회 API를 호출하여 응답 결과를 각 위치에 맞게 출력한다.

const fetchBookLoans = async (page, size) => {

  setLoading(true);
  setError(null);

  try {
    const response = await axios.get(
      "http://localhost:8080/api/v1/user/me/loans",
      {
        params: {
          page: page,
          size: size,
        },
        withCredentials: true,
        headers: {
          Accept: "application/json",
        }
      }
    );

    console.log(response.data.data);
    setData(response.data.data.content);
    setTotalPages(response.data.data.totalPages || 1);
  } catch (error) {
    console.log("Error: ", error.response);
    setError(error.response);
  } finally {
    setLoading(false);
  }

};
{data.map((item) => (
  <div 
    key={item.id}
    className="flex flex-row w-full border border-gray-200 p-3 mb-2"
  >
    <div className="flex w-[120px] items-start">
      <img src="https://placehold.co/420x600" alt="" className="w-auto block h-auto" />
    </div>
    <div className=" flex flex-col justify-start self-start leading-6 text-[15px] ml-2 text-gray-700">
      <div className="font-bold text-black">{item.bookTitle}</div>
      <div className="flex sm:flex-row flex-col">
        <div>{item.author}</div>
        <div className="mx-2 hidden sm:block">|</div>
        <div>{item.publisher}</div>
      </div>
      <div>위치:<span className="ml-1">{item.location}</span></div>
      <div>상태: 
        <span className="text-blue-700 ml-1">
          { bookStatus(item.status) }
        </span>
      </div>
      <div className="flex sm:flex-row flex-col">
        <div>대출일:<span className="ml-1">{item.loanDate.split('T', 1)}</span></div>
        <div className="mx-2 hidden sm:block">|</div>
        <div>반납일:<span className="text-red-700 ml-1">{item.returnDate === null ? " ": item.returnDate.split('T', 1)}</span></div>
      </div>
      <div>대출자:<span className="ml-1">{item.borowwer}</span></div>
      <div>리뷰작성:<span className="text-green-700 ml-1">미작성</span></div>
    </div>
  </div>
))}

 

- 도서 대출 상태는 switch문을 사용하여 처리했다.

let bookStatus = (status) => {
  switch(status) {
    case "LOANED":
      return "대출중";
    case "RETURNED":
      return "반납 완료";
    case "OVERDUE":
      return "연체됨";
    case "LOST":
      return "분실됨";
    default:
      return "";
  }
};

 

- 페이징 처리

// 페이징 - 이전 버튼
const handlePrev = () => {
  if (page > 0) {
    setPage(page - 1);
    fetchBookLoans(currentFilter, page - 1);
  }
}

// 페이징 - 다음 버튼
const handleNext = () => {
  if (page < totalPages - 1) {
    setPage(page + 1);
    fetchBookLoans(currentFilter, page + 1);
  }
}

// 페이징 - 번호
const handlePageClick = (pageNumber) => {
  setPage(pageNumber);
}
<div>
  <button
    onClick={ handlePrev }
    disabled={page === 0 || totalPages === 0}
    className="px-3 py-1 cursor-pointer disabled:opacity-50"
  >이전</button>
  {[...Array(totalPages)].map((_, i) => (
    <button
      key={i}
      onClick={() => handlePageClick(i)}
      className={`px-[10px] py-[6px] mx-[3px] text-base cursor-pointer ${
        i === page ? "text-teal-600 font-bold" : ""
      }`}
    >{i + 1}</button>
  ))}
  <button
    onClick={ handleNext }
    disabled={page === totalPages - 1 || totalPages === 0}
    className="px-3 py-1 cursor-pointer disabled:opacity-50"
  >이후</button>
</div>

2. 도서 대출 전체 조회 시 응답 결과 DTO 필드 수정

- 대출자, 도서 위치, 도서 상태를 관련 응답 DTO에 추가

@Getter
public class UserLoanListResDTO {
  private Long id;
  private String bookTitle;
  private String author;
  private String publisher;
  private LocalDate publishedDate;
  private String location;
  private LocalDateTime loanDate;
  private LocalDateTime returnDate;
  private String borrower;
  private LoanStatus status;

  public UserLoanListResDTO(Loan loan) {
    this.id = loan.getId();
    this.bookTitle = loan.getBook().getTitle();
    this.author = loan.getBook().getAuthor();
    this.publisher = loan.getBook().getPublisher();
    this.publishedDate = loan.getBook().getPublishedDate();
    this.location = loan.getBook().getLocation();
    this.loanDate = loan.getLoanDate();
    this.returnDate = loan.getReturnDate();
    this.borrower = loan.getUser().getUsername();
    this.status = loan.getStatus();
  }
}