KDT-IaaS-Class-One-Group / KDT-IaaS-1team-ERP

0 stars 2 forks source link

admin - list 페이지네이션 코드 수정 #76

Open seunghee1108 opened 8 months ago

seunghee1108 commented 8 months ago

admin/app/list/page.tsx

"use client";

import React, { useState, useEffect, useCallback } from "react";

interface Product {
  cateName: string;
  productName: string;
  price: string;
  stock: string;
  productKey: number;
}

const pageSize = 10;

export default function List() {
  const [products, setProducts] = useState<Product[]>([]);
  const [selectedProducts, setSelectedProducts] = useState<number[]>([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [searchTerm, setSearchTerm] = useState("");
  // const [totalPages, setTotalPages] = useState(1);
  const [pageInfo, setPageInfo] = useState({
    currentPage: 1,
    pageSize: 10,
    totalPages: 1,
  });

  const fetchData = useCallback(
    async (page: number, term: string = "") => {
    // async (page: number) => {
      try {
        let apiUrl = `/product?page=${page}&pageSize=${pageSize}`;

        if (term) {
          apiUrl += `&searchTerm=${term}`;
        }

        const response = await fetch(apiUrl);
        const data = await response.json();

        setProducts(data.products);
        setPageInfo({
          currentPage: data.pageInfo.currentPage,
          pageSize: data.pageInfo.pageSize,
          totalPages: data.pageInfo.totalPages,
        });
      } catch (error) {
        console.error("상품 정보를 가져오는데 실패했습니다.", error);
      }
    },
    []
  );

  const handlePageChange = (newPage: number) => {
    setCurrentPage(newPage);
    // setCurrentPage(newPage);
    // fetchData(newPage, searchTerm);
  };

  const handleCheckboxChange = (productKey: number) => {
    setSelectedProducts((prevSelected) => {
      const isSelected = prevSelected.includes(productKey);
      let updatedSelected: number[];

      if (isSelected) {
        updatedSelected = prevSelected.filter((key) => key !== productKey);
      } else {
        updatedSelected = [...prevSelected, productKey];
      }

      return updatedSelected;
    });
  };

  const handleDelete = async () => {
    try {
      if (selectedProducts.length === 0) {
        console.error("선택한 상품이 없습니다.");
        return;
      }

      const deleteRequests = selectedProducts.map((productKey) => {
        return fetch(`/deleteProduct/${productKey}`, {
      // const deleteRequests = selectedProducts.map((index) => {
      //   const productId = products[index].productKey;
      //   return fetch(`/deleteProduct/${productId}`, {
          method: "DELETE",
        }).then((response) => {
          if (!response.ok) {
            throw new Error("상품 삭제에 실패했습니다.");
          }
          return response.json();
        });
      });

      const deleteResults = await Promise.all(deleteRequests);

      const isDeleteSuccess = deleteResults.every(
        (result) => result && result.message === "상품이 성공적으로 삭제되었습니다."
        // (result) => result.message === "상품이 성공적으로 삭제되었습니다."
      );

      if (isDeleteSuccess) {
        const updatedProducts = products.filter(
          // (_, index) => !selectedProducts.includes(index)
          (product) => !selectedProducts.includes(product.productKey)
        );
        setProducts(updatedProducts);
        setSelectedProducts([]);

        // 삭제 후 currentPage를 1로 업데이트
        setCurrentPage(1);

        fetchData(1, searchTerm); // 삭제 후 첫 페이지의 데이터를 가져옵니다.
        // fetchData(1); // Fetch data for the first page after deletion
      } else {
        console.error("일부 상품이 삭제되지 않았습니다.", deleteResults);
        throw new Error("일부 상품이 삭제되지 않았습니다.");
      }
    } catch (error) {
      console.error("상품 삭제 중 오류 발생:", error);
    }
  };

  const handleSearch = () => {
    // 검색 버튼 클릭 시 첫 페이지의 데이터를 가져옵니다.
    setCurrentPage(1);
    fetchData(1, searchTerm);
  };

  useEffect(() => {
      // 검색어가 변경될 때 자동으로 검색
      const searchTimer = setTimeout(() => {
        fetchData(1, searchTerm);
      }, 500); // 500 milliseconds 딜레이

      // cleanup 함수: 이전 타이머를 제거하여 중복 호출 방지
      return () => clearTimeout(searchTimer);
    }, [searchTerm, fetchData]);

  //   setSearchTerm("");
  // }, []);

  useEffect(() => {
      // 초기 렌더링 시 첫 페이지의 데이터를 가져옵니다.
      fetchData(1);
    }, [fetchData]);
  //   fetchData(pageInfo.currentPage);
  // }, [fetchData, pageInfo.currentPage]);

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-4xl font-bold mb-6">상품 목록</h1>
      <div className="flex items-center mb-4">
      <input
        type="text"
        placeholder="상품명으로 검색"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        className="border border-gray-300 rounded-md text-black px-10 py-2.5 mr-4"
      />
      <button
        className="bg-blue-500 text-white px-10 py-2.5 rounded-md"
        onClick={handleSearch}
      >
        검색
      </button>
    </div>

      <button
        className="bg-blue-500 text-white px-10 py-2.5 rounded-md mb-4"
        onClick={handleDelete}
      >
        상품 삭제
      </button>

      <table className="mt-4 border-collapse border w-full">
        <thead className="border-b-2 border-solid border-gray-200">
          <tr className="text-lg md:text-xl bg-gray-200">
            <th className="p-2 text-2xl text-center w-1/12 border-solid">
              선택
            </th>
            <th className="p-2 text-2xl text-center w-2/12">카테고리</th>
            <th className="p-2 text-2xl text-center w-3/12">상품명</th>
            <th className="p-2 text-2xl text-center w-2/12">가격</th>
            <th className="p-2 text-2xl text-center w-2/12">재고</th>
          </tr>
        </thead>
        <tbody className="py-4">
          {Array.isArray(products) &&
            products.map((product, index) => (
              <tr
                key={index}
                className={`${
                  index % 2 === 0 ? "bg-gray-100" : "bg-white"
                } text-base md:text-lg  px-4 py-4 rounded-md`}
                style={{ lineHeight: "2.5" }}
              >
                <td className="text-center">
                  <input
                    type="checkbox"
                    checked={selectedProducts.includes(product.productKey)}
                    onChange={() => handleCheckboxChange(product.productKey)}
                  />
                </td>
                <td className="text-center">{product.cateName}</td>
                <td className="text-center">{product.productName}</td>
                <td className="text-center">{product.price}원</td>
                <td className="text-center">{product.stock}</td>
              </tr>
            ))}
        </tbody>
      </table>

      <div className="mt-4 flex items-center justify-center space-x-2 fixed bottom-0 left-0 w-full bg-white p-4">
        {Array.from(
          { length: pageInfo.totalPages },
          (_, index) => index + 1
        ).map((pageNumber) => (
          <button
            key={pageNumber}
            className={`w-10 h-10 px-2 border rounded ${
              pageNumber === pageInfo.currentPage
                ? "bg-blue-500 text-white"
                : "border-gray-300 hover:bg-gray-100"
            }`}
            onClick={() => handlePageChange(pageNumber)}
          >
            {pageNumber}
          </button>
        ))}
      </div>
    </div>
  );
}
csm009177 commented 8 months ago

admin 루트 레이아웃 수정부분

admin\app\layout.tsx

return (

{children}

) }

모든 버튼 공통 수정부분 return 이하 return ( <button className="flex justify-center items-center bg-gray-300 w-32 h-20 rounded-md text-lg transition duration-300 ease-in-out hover:bg-gray-400 mb-5"

admin\app\apply\page.tsx 의 리턴 이하 return (

상품 등록

); }

admin\app\chart\page.tsx 리턴 이하

return (

{selectedChart === "SaleChart" && }
{selectedChart === "TopProductSection" && }
{selectedChart === "ProductPreferenceChart" && }
{selectedChart === "CategorySalesChart" && }

); }

admin\app\list\page.tsx 리턴 이하

return (

상품 목록

setSearchTerm(e.target.value)} className="border border-gray-300 rounded-md text-black px-10 py-2.5 mr-4" />
{Array.isArray(products) && products.map((product, index) => ( ))}
선택 카테고리 상품명 가격 재고
handleCheckboxChange(product.productKey)} /> {product.cateName} {product.productName} {product.price}원 {product.stock}
{Array.from( { length: pageInfo.totalPages }, (_, index) => index + 1 ).map((pageNumber) => ( ))}

); }

admin\app\manage\page.tsx 리턴 이하

return (

사용자 목록

setSearchTerm(e.target.value)} className="border border-gray-300 rounded-md text-black px-10 py-2.5 ml-4 mb-4" /> setGiveCash(e.target.value)} placeholder="캐시를 입력하세요" className="border p-2 mr-2 " />
{Array.isArray(users) && users.map((user, index) => ( ))}
선택 이름 아이디 캐시 가입일 활성화
toggleCheckbox(index)} /> {user.name} {user.username} {user.cash} {new Date(user.addDate) .toISOString() .replace("T", " ") .substr(0, 19)}
{Array.from({ length: pageInfo.totalPages }, (_, index) => index + 1).map( (pageNumber) => ( ) )}

); }

admin\app\qna\page.tsx 리턴 이하

return (

고객 문의

{showForm && (
{/* Modal Form */}
{/* Close button */} ×
)}
{" "} {/* Increased margin-top for spacing */} {boards.map((board, index) => ( ))}
titleKey adddate username title reply Actions
{board.titleKey} {formatDateTime(board.adddate)} {board.username} {board.title} {board.reply}
{selectedBoard && (
×

titleKey : {selectedBoard.titleKey}

adddate : {formatDateTime(selectedBoard.adddate)}
username : {selectedBoard.username}
title : {selectedBoard.title}
content : {selectedBoard.content}
reply : {selectedBoard.reply}
setEditedReply((prev) => ({ ...prev, [selectedBoard.username]: e.target.value, })) } className="border p-2 mt-2 w-full" />
)}
{Array.from( { length: pageInfo.totalPages }, (_, index) => index + 1 ).map((pageNumber) => ( ))}

); }

admin\app\ui\saleChart.tsx 리턴 이하 return (

총 판매량

); }; admin\app\ui\totalChart.tsx 리턴 이하 return (

분류별 판매량(30일)

); }

csm009177 commented 8 months ago

admin\app\ui\globals.css 이하 추가

.animate-fade-in { animation: fadeIn 1s ease-out; animation-fill-mode: forwards; }

.charts { height:400px; width: 400px; }

.cate-chart { height: 400px; width: 400px; }

.pre-chart { height: 400px; width: 400px; }