Web Project/booking

Select/Update a single room (Front/Backend)

hmmmmmmmmmmmm 2024. 11. 22. 21:34

 

 

· 개별 객실 조회 (백엔드)

 

RoomController.java

// 객실 개별 조회
@GetMapping("/room/{roomId}")
public ResponseEntity<Optional<RoomResponse>> getRoomById(@PathVariable Long roomId) {

    // roomService를 통해 roomId에 해당하는 객실 정보를 Optional<Room>으로 가져온다
    // Optional<Room>: 해당 ID의 객실이 있을 수도 있고 없을 수도 있다
    Optional<Room> theRoom = roomService.getRoomById(roomId);

    // 데이터가 없으면 예외 발생
    return theRoom.map((room) -> {
        RoomResponse roomResponse = getRoomResponse(room);
        return ResponseEntity.ok(Optional.of(roomResponse));
    }).orElseThrow(() -> new ResourceNotFoundException("해당 객실이 없습니다"));
}

// Room 객체를 RoomResponse로 변환
private RoomResponse getRoomResponse(Room room) {

    // 특정 Room의 모든 예약 정보 가져오기
    List<BookedRoom> bookings = getaAllBookingsByRoomId(room.getId());
    // 각 예약 정보(bookings)를 BookingResponse 객체로 변환
    List<BookingResponse> bookingInfo = bookings.stream()
            .map(booking -> new BookingResponse(booking.getBookingId(),
                    booking.getCheckInDate(),
                    booking.getCheckOutDate(),
                    booking.getBookingConfirmationCode()))
            .toList();
    byte[] photoBytes = null;
    // Room 객체의 객실 이미지 데이터
    Blob photoBlob = room.getPhoto();
    if (photoBlob != null) {
        try {
            // BLOB 데이터 -> byte[](바이트 배열)로 변환
            photoBytes = photoBlob.getBytes(1, (int) photoBlob.length());
        } catch (SQLException e) {
            e.printStackTrace(); // 에러 로그 출력
            throw new PhotoRetrievalException("객실 이미지 불러오는 중 오류 발생");
        }
    }

    // Room 정보를 기반으로 RoomResponse 객체 생성 후 반환
    return new RoomResponse(room.getId(),
                            room.getRoomType(),
                            room.getRoomPrice(),
                            room.isBooked(),
                            photoBytes,
                            bookingInfo);
}

 

 

RoomServiceImpl.java

// 객실 개별 조회
@Override
public Optional<Room> getRoomById(Long roomId) {
    return Optional.of(roomRepository.findById(roomId).get());
}

 

 

 

 

 

 

· 개별 객실 수정  (백엔드)

 

RoomController.java

// 객실 개별 수정
@PutMapping("/update/{roomId}")
public ResponseEntity<RoomResponse> updateRoom(@PathVariable Long roomId,
                                               @RequestParam(required = false) String roomType,
                                               @RequestParam(required = false) BigDecimal roomPrice) throws SQLException, IOException {

    // roomService를 통해 객실 정보 수정
    Room theRoom = roomService.updateRoom(roomId, roomType, roomPrice);
    // 수정된 Room 객체를 roomResponse(DTO)로 변환 --> 클라이언트에 전달
    RoomResponse roomResponse = getRoomResponse(theRoom);

    return ResponseEntity.ok(roomResponse);

}

 

 

 

RoomServiceImpl.java

// 객실 개별 수정
@Override
public Room updateRoom(Long roomId, String roomType, BigDecimal roomPrice) {
    Room room = roomRepository.findById(roomId)
                    .orElseThrow(() -> new ResourceNotFoundException("해당 객실이 없습니다"));

    if (roomType != null) {
        room.setRoomType(roomType);
    }

    if (roomPrice != null) {
        room.setRoomPrice(roomPrice);
    }

    return roomRepository.save(room);
}

 

 

 

 

· 개별 객실 조회/수정  (클라이언트)

 

ApiFunctions.js

// 객실 개별 조회
export async function getRoomById(roomId) {
    
    try {
        const result = await api.get(`/rooms/room/${roomId}`)
        return result.data
    }
    catch(error) {
        throw new Error(`개별 객실 정보를 가져오는데 실패했습니다: ${error.message}`)
    }
}


// 객실 개별 수정
export async function updateRoom(roomId, roomData) {

    const formData = new FormData()
    formData.append("roomType", roomData.roomType)
    formData.append("roomPrice", roomData.roomPrice)

    const response = await api.put(`/rooms/update/${roomId}`, formData, {
        headers: {
            'Content-Type': 'multipart/form-data',
        }
    })
    
    return response
}

 

 

 

EditRoom.jsx

// 객실 수정 폼

import { useEffect, useState } from "react";
import { getRoomById, updateRoom } from "../utils/ApiFunctions";
import { Link, useParams } from "react-router-dom";

export default function EditRoom() {
    const [room, setRoom] = useState({
        roomType: "",
        roomPrice: "",
    });

    const [imagePreview, setImagePreview] = useState("");
    const [successMessage, setSuccessMessage] = useState("");
    const [errorMessage, setErrorMessage] = useState("");

    const { roomId } = useParams();

    // 객실 유형 데이터
    const roomTypes = [
        "Suite room",
        "Family room",
        "Penthouse",
        "Deluxe room",
        "Superior room",
    ];

    const handleInputChange = (event) => {
        const { name, value } = event.target;
        setRoom({
            ...room,
            [name]: value,
        });
    };

    const handleRoomTypeChange = (type) => {
        setRoom({
            ...room,
            roomType: type,
        });
    };

    useEffect(() => {
        const fetchRoom = async () => {
            try {
                // 객실 개별 조회
                const roomData = await getRoomById(roomId);
                setRoom(roomData);
                
                // Base64 이미지 데이터 검증 및 설정
                if (roomData.photo) {
                    // 이미 data:image 접두사가 있는지 확인
                    const photoData = roomData.photo.startsWith('data:image') 
                        ? roomData.photo
                        //  'data:image/jpeg;base64,' 접두사를 붙이기 --> 브라우저가 Base64로 인코딩된 이미지 표시 용도
                        : `data:image/jpeg;base64,${roomData.photo}`;
                    setImagePreview(photoData);
                }
            } catch (error) {
                console.error("Error fetching room:", error);
                setErrorMessage("객실 정보를 불러오는데 실패했습니다.");
            }
        };
    
        fetchRoom();
    }, [roomId]);

    
    // 객실 수정 제출
    const handleSubmit = async (e) => {
        e.preventDefault();
    
        try {
            // 객실 수정 api 호출
            const response = await updateRoom(roomId, room);
            if (response.status === 200) {
                setSuccessMessage("객실이 수정되었습니다!");
                const updatedRoomData = await getRoomById(roomId);
                setRoom(updatedRoomData);
                
                // 이미지 데이터 업데이트
                if (updatedRoomData.photo) {
                    const photoData = updatedRoomData.photo.startsWith('data:image') 
                        ? updatedRoomData.photo
                        : `data:image/jpeg;base64,${updatedRoomData.photo}`;
                    setImagePreview(photoData);
                }
    
                setErrorMessage("");
            } else {
                setErrorMessage("Error updating room");
            }
        } catch (error) {
            console.error(error);
            setErrorMessage(error.message);
        }
    };

    return (
        <section className="w-full text-center">
            <h2 className="text-3xl font-bold my-6">기존 객실 수정</h2>
    
            {successMessage && (
                <div className="fixed top-4 left-1/2 transform -translate-x-1/2 text-green-500 py-2 px-4 rounded shadow-lg text-center">
                    {successMessage}
                </div>
            )}

            {successMessage && (
                <div className="fixed top-4 left-1/2 transform -translate-x-1/2 text-red-500 py-2 px-4 rounded shadow-lg text-center">
                    {errorMessage}
                </div>
            )}
    
            <div>
                {imagePreview && (
                    <img
                        src={imagePreview}
                        alt="Preview of Room Photo"
                        className="h-64 object-cover mx-auto my-4 rounded-md"
                    />
                )}
            </div>

            <form className="flex flex-col space-y-6" onSubmit={handleSubmit}>
                <div>
                    <label htmlFor="roomType" className="block text-gray-700 font-medium mb-2">
                        Room Type
                    </label>
                    
                    <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 ${
                                    room.roomType === type
                                        ? "bg-blue-600 text-white"
                                        : "bg-white text-gray-700 border-gray-300"
                                }`}
                                onClick={() => handleRoomTypeChange(type)}
                            >
                                <input
                                    type="radio"
                                    name="roomType"
                                    value={type}
                                    checked={room.roomType === type}
                                    onChange={() => handleRoomTypeChange(type)}
                                    className="hidden"
                                />
                                {type}
                            </label>
                        ))}
                    </div>
                </div>
    
                <div>
                    <label htmlFor="roomPrice" className="block text-gray-700 font-medium mb-2">
                        Room Price
                    </label>
                    <input
                        className="w-full p-3 border border-gray-300 rounded-md"
                        required
                        id="roomPrice"
                        name="roomPrice"
                        type="number"
                        value={room.roomPrice}
                        onChange={handleInputChange}
                    />
                </div>
    
                <div className="flex gap-4">
                    <Link
                        to="/existing-rooms"
                        className="w-full py-3 bg-gray-300 text-gray-700 font-semibold rounded-md hover:bg-gray-400 transition text-center"
                    >
                        뒤로가기
                    </Link>
                    <button
                        className="w-full py-3 bg-blue-600 text-white font-semibold rounded-md hover:bg-blue-700 transition"
                        type="submit"
                    >
                        객실 수정
                    </button>
                </div>
            </form>
        </section>
    );
}

 

 

 

'Web Project > booking' 카테고리의 다른 글

Select all rooms (Frontend) (2) - 고객용  (0) 2024.11.23
Add navbar / footer  (0) 2024.11.23
Delete a single room (Frontend)  (0) 2024.11.18
Delete a single room (Backend)  (0) 2024.11.17
Select all rooms (Frontend)  (0) 2024.11.15