· 기능 개요
객실 목록 조회, 필터링, 페이징
ApiFunctions.js
// 객실 전체 조회
export async function getAllRooms() {
try {
const result = await api.get("/rooms/all-rooms")
return result.data;
}
catch(error) {
throw new Error("전체 객실 정보를 가져오는데 실패했습니다")
}
}
ExistingRooms.jsx
// 기존 객실 목록
import { useState } from "react"
import { deleteRoom, getAllRooms } from "../utils/ApiFunctions";
import { useEffect } from "react";
import RoomFilter from "../common/RoomFilter";
import RoomPaginator from "../common/RoomPaginator";
import { FaEdit, FaEye, FaTrashAlt } from "react-icons/fa";
import { Link } from "react-router-dom";
export default function ExistingRooms() {
// 전체 객실 목록
const [rooms, setRooms] = useState([]);
// 현재 페이지 번호
const [currentPage, setCurrentPage] = useState(1);
// 페이지당 표시할 객실 수 (8개, 고정 값)
const [roomsPerPage] = useState(8);
const [isLoading, setIsLoading] = useState(false);
// 필터링된 객실 목록
const [filteredRooms, setFilteredRooms] = useState([]);
const [successMessage, setSuccessMessage] = useState("");
const [errorMessage, setErrorMessage] = useState("");
useEffect(() => {
fetchRooms();
}, [])
// 객실 전체 조회 api 호출
const fetchRooms = async() => {
setIsLoading(true)
try {
const result = await getAllRooms()
setRooms(result)
setFilteredRooms(result)
setIsLoading(false)
}
catch(error) {
console.error(error)
}
}
// 객실 개별 삭제 api 호출
const handleDelete = async(roomId) => {
try {
const result = await deleteRoom(roomId)
if (result === "") {
setSuccessMessage(`객실 번호 ${roomId} 삭제 성공`)
fetchRooms()
}
else {
console.error(`객실 번호 ${roomId} 삭제 실패`)
}
}
catch(error) {
setErrorMessage(error.message)
}
setTimeout(() => {
setSuccessMessage("")
setErrorMessage("")
}, 3000)
}
// 페이지 번호 클릭
const handlePaginationClick = (pageNumber) => {
setCurrentPage(pageNumber)
}
// 총 페이지 계산
const calculateTotalPages = (filteredRooms, roomsPerPage, rooms) => {
const totalRooms = filteredRooms.length > 0 ? filteredRooms.length : rooms.length
// 총 객실 수를 페이지당 객실 수로 나누어 올림
return Math.ceil(totalRooms / roomsPerPage)
}
// 현재 페이지에서 첫 번째로 보여줄 객실의 인덱스(순서 번호)
const indexOfFirstRoom = (currentPage - 1) * roomsPerPage
// 현재 페이지에서 마지막으로 보여줄 객실의 인덱스
const indexOfLastRoom = currentPage * roomsPerPage
// 현재 페이지에 해당하는 객실 목록(최대 8개)
const currentRooms = filteredRooms.slice(indexOfFirstRoom, indexOfLastRoom)
return (
<>
{successMessage && (
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 bg-green-500 text-white py-2 px-4 rounded shadow-lg text-center">
{successMessage}
</div>
)}
{isLoading ? (
<p className="text-center text-gray-600">Loading...</p>
) : (
<section className="container mx-auto p-5">
<div className="text-center mb-8">
<h2 className="text-4xl font-bold text-gray-800">기존 객실 목록</h2>
</div>
{/* 객실 타입 필터링 */}
<div className="flex justify-center mb-6">
<div className="w-full">
<RoomFilter
data={rooms}
setFilteredData={setFilteredRooms}
/>
</div>
</div>
{/* 객실 테이블 */}
<div className="overflow-x-auto">
<table className="min-w-full bg-white border rounded-lg shadow-md">
<thead className="bg-gray-100">
<tr>
<th className="px-6 py-3 text-gray-700 font-semibold text-sm">ID</th>
<th className="px-6 py-3 text-gray-700 font-semibold text-sm">Room Type</th>
<th className="px-6 py-3 text-gray-700 font-semibold text-sm">Room Price</th>
<th className="px-6 py-3 text-gray-700 font-semibold text-sm">Actions</th>
</tr>
</thead>
<tbody>
{currentRooms.map((room) => (
<tr key={room.id} className="border-t text-center">
<td className="px-6 py-4">{room.id}</td>
<td className="px-6 py-4">{room.roomType}</td>
<td className="px-6 py-4">{room.roomPrice}</td>
<td className="px-6 py-4 flex justify-center items-center gap-4">
<Link
to={`/view-room/${room.id}`}
className="text-blue-500 hover:text-blue-700"
>
<FaEye />
</Link>
<Link
to={`/edit-room/${room.id}`}
className="text-yellow-500 hover:text-yellow-700"
>
<FaEdit />
</Link>
<button
className="text-red-500 hover:text-red-700"
onClick={() => handleDelete(room.id)}
>
<FaTrashAlt />
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* 객실 추가 버튼 */}
<div className="flex justify-end mt-4">
<Link
to="/add-room"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
객실 추가
</Link>
</div>
{/* 객실 목록 페이징 */}
<div className="flex justify-center mt-8 left-0 right-0 bg-white">
<RoomPaginator
currentPage={currentPage}
totalPages={calculateTotalPages(filteredRooms, roomsPerPage, rooms)}
onPageChange={handlePaginationClick}
/>
</div>
</section>
)}
</>
);
}
RoomFilter.jsx
// 객실 타입 필터링
import { useState } from "react";
export default function RoomFilter({ data, setFilteredData }) {
// 사용자가 선택한 필터
const [selectedType, setSelectedType] = useState("");
// 필터 적용
const handleSelect = (type) => {
setSelectedType(type);
// 필터 All 선택 --> 전체 데이터 부모에 전달
if (type === "") {
setFilteredData(data);
}
else {
// 선택한 타입과 일치하는 객실만 필터링
const filteredRooms = data.filter((room) => room.roomType.toLowerCase().includes(type.toLowerCase()));
// 필터링된 데이터를 부모에 전달
setFilteredData(filteredRooms);
}
};
// 객실 타입 목록
const roomTypes = [
// All을 위한 빈 문자열
"",
// 중복 없는(Set) 객실 타입 목록
...new Set(data.map((room) => room.roomType))
];
return (
<div className="mt-4">
<div className="flex space-x-2 justify-center mx-auto">
{roomTypes.map((type, index) => (
<label
key={index}
className={`px-4 py-2 border rounded-md cursor-pointer ${
selectedType === type
? "bg-blue-600 text-white"
: "bg-white text-gray-700 border-gray-300"
}`}
onClick={() => handleSelect(type)}
>
<input
type="radio"
name="roomType"
value={type}
checked={selectedType === type}
// 변경 시 필터 적용
onChange={() => handleSelect(type)}
className="hidden"
/>
{/* 버튼 텍스트 --> 빈 문자열이면 All로 표시 */}
{type || "All"}
</label>
))}
</div>
</div>
);
}
RoomPaginator.jsx
// 객실 목록 페이징
export default function RoomPaginator({ currentPage, totalPages, onPageChange }) {
// 총 페이지 수를 기반으로 페이지 번호 배열 생성 --> toalPages가 5면, pageNumbers는 [1, 2, 3, 4, 5]
const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1);
return (
<nav className="flex justify-center mt-8">
<ul className="flex space-x-2">
{/* 페이지 번호 목록 버튼 */}
{pageNumbers.map((pageNumber) => (
<li key={pageNumber}>
<button
onClick={() => onPageChange(pageNumber)}
className={`px-4 py-2 rounded-md text-sm font-semibold focus:outline-none
${currentPage === pageNumber
? "bg-blue-500 text-white"
: "bg-gray-200 text-gray-700 hover:bg-gray-300"
}`}
>
{pageNumber}
</button>
</li>
))}
</ul>
</nav>
);
}
'Web Project > booking' 카테고리의 다른 글
Delete a single room (Frontend) (0) | 2024.11.18 |
---|---|
Delete a single room (Backend) (0) | 2024.11.17 |
Select all rooms (Backend) (0) | 2024.11.09 |
Add new room (Frontend) (0) | 2024.11.08 |
Select room types (Backend) (0) | 2024.11.08 |