diff --git a/frontend/src/api/books.ts b/frontend/src/api/books.ts index 45d290a0..20552415 100644 --- a/frontend/src/api/books.ts +++ b/frontend/src/api/books.ts @@ -78,6 +78,9 @@ export const useBooksAPI = () => { const postBookBooking = async (bookId: string | undefined) => await api.post(`/reservation/${bookId}`); + // check booking + const getCheckBookBooking = async (bookId: number | string | undefined) => + await axiosInstance.get(`/reservation/check/${bookId}`); return { getAllBooksList, getBookDetail, @@ -86,5 +89,6 @@ export const useBooksAPI = () => { deleteBook, postBookRental, postBookBooking, + getCheckBookBooking, }; }; diff --git a/frontend/src/api/hooks/books/useCheckBooking.ts b/frontend/src/api/hooks/books/useCheckBooking.ts new file mode 100644 index 00000000..80a75d88 --- /dev/null +++ b/frontend/src/api/hooks/books/useCheckBooking.ts @@ -0,0 +1,15 @@ +import { useQuery } from '@tanstack/react-query'; +import { useBooksAPI } from '../../books'; + +export const useGetCheckBooking = (bookId: number | string | undefined) => { + const { getCheckBookBooking } = useBooksAPI(); + const { data: checkBooking } = useQuery({ + refetchOnWindowFocus: false, + refetchOnMount: false, + retry: 0, + cacheTime: 0, + queryKey: ['bookCheckBooking'], + queryFn: () => getCheckBookBooking(bookId).then(res => res.data), + }); + return { checkBooking }; +}; diff --git a/frontend/src/api/hooks/books/useGetBookDetail.ts b/frontend/src/api/hooks/books/useGetBookDetail.ts index 7a21308b..fb2ffa34 100644 --- a/frontend/src/api/hooks/books/useGetBookDetail.ts +++ b/frontend/src/api/hooks/books/useGetBookDetail.ts @@ -37,7 +37,6 @@ export const useGetBookDetail = ( } = useQuery({ queryKey: [bookId, 'bookDetail'], queryFn: () => getBookDetail(bookId, isLogin), - initialData: initialState, }); return { bookDetailData, isLoading, refetchBookDetail }; diff --git a/frontend/src/components/Books/BookDetail.tsx b/frontend/src/components/Books/BookDetail.tsx index 781433a4..3814e514 100644 --- a/frontend/src/components/Books/BookDetail.tsx +++ b/frontend/src/components/Books/BookDetail.tsx @@ -48,7 +48,6 @@ const BookDetail = ({ book, merchant, refetchBookDetail }: BookDetailProps) => { } if (merchant && book) { axiosCreateRoom(merchant?.merchantId, id, book?.bookId).then(res => { - // console.log(res); navigate(`/chats/${res}`); }); } @@ -132,15 +131,12 @@ const BookDetail = ({ book, merchant, refetchBookDetail }: BookDetailProps) => { - {isLogin && merchant?.merchantId !== id ? ( - - 채팅 - - ) : ( - - 채팅 - - )} + + 채팅 + @@ -149,7 +145,6 @@ const BookDetail = ({ book, merchant, refetchBookDetail }: BookDetailProps) => { 대여 정보 - {/* | */} @@ -233,15 +228,13 @@ interface ChatButtonProps { isLogin: boolean; } -const ChatButton = styled.button` +const ChatButton = styled(Button)` background-color: ${props => (props.isLogin ? '#ffc700' : '#a7a7a7')}; color: black; - border: none; padding: 0.5rem 1rem; - border-radius: 5px; cursor: pointer; :hover { - background-color: ${props => (props.isLogin ? '#e8b601' : '#8c8c8c')}; + background-color: ${props => (props.isLogin ? '#e8b601' : '#a7a7a7')}; } `; diff --git a/frontend/src/components/Member/ReservationBookList.tsx b/frontend/src/components/Member/ReservationBookList.tsx index c1bc30a3..2d3ec56b 100644 --- a/frontend/src/components/Member/ReservationBookList.tsx +++ b/frontend/src/components/Member/ReservationBookList.tsx @@ -4,7 +4,6 @@ import { useNavigate } from 'react-router-dom'; import Animation from '../Loading/Animation'; import Button from '../common/Button'; -import ButtonStatus from '../Merchant/ButtonStatus'; import { useGetReservList } from '../../api/hooks/member/useGetReservList'; import { useDeleteReserv } from '../../api/hooks/books/useDeleteReserv'; @@ -18,18 +17,6 @@ const ReservationBookList = () => { navigate(`/books/${id}`); }; - // const handleClickIcon = ( - // e: React.MouseEvent, - // bookId: number, - // ) => { - // e.stopPropagation(); - // if (window.confirm('정말 취소하시겠습니까?')) { - // mutate(bookId); - // } else { - // return; - // } - // }; - const { deleteMutate } = useDeleteReserv(cancelId); const { @@ -61,7 +48,7 @@ const ReservationBookList = () => { const isTrue = window.confirm(`'${title}' 도서의 예약을 취소하시겠습니까?`); if (!isTrue) return; setCancelId(reservationId); - // deleteMutate(); + deleteMutate(); }; useEffect(() => { @@ -127,17 +114,12 @@ const ReservationBookList = () => { - {/* className={`${isFetchingNextPage ? '' : 'hidden'}`}> */} {isFetchingNextPage ?

Loading more books ...

: ''}
); }; -const Box = styled.div` - /* padding: 0 1rem; */ -`; - const Container = styled.div` width: 90%; display: flex; @@ -169,8 +151,6 @@ const InfoWrapped = styled.div` justify-content: space-between; align-items: center; p { - /* font-size: ${props => props.theme.fontSizes.paragraph}; - margin-left: 1rem; */ font-size: 13px; margin-left: 1rem; display: flex; @@ -178,7 +158,6 @@ const InfoWrapped = styled.div` padding-top: 10px; } .bookname { - /* font-size: ${props => props.theme.fontSizes.subtitle}; */ font-size: 16px; font-weight: 600; padding-top: 0px; @@ -193,7 +172,6 @@ const EmptyBox = styled.div` align-items: center; p { font-size: ${props => props.theme.fontSizes.subtitle}; - /* font-size: 16px; */ font-weight: 600; } `; diff --git a/frontend/src/pages/BooksBookingPage.tsx b/frontend/src/pages/BooksBookingPage.tsx index 33b35e78..3e9e9bae 100644 --- a/frontend/src/pages/BooksBookingPage.tsx +++ b/frontend/src/pages/BooksBookingPage.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; -import { useLocation, useParams } from 'react-router-dom'; -import { useState } from 'react'; +import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import { useEffect, useState } from 'react'; // components import { @@ -17,6 +17,9 @@ import { import { calcCalendarDate } from 'utils/calcCalendarDate'; import { usePostBookBooking } from 'api/hooks/books/usePostBookBooking'; +import { useGetCheckBooking } from 'api/hooks/books/useCheckBooking'; +import notify from 'utils/notify'; +import { useDispatch } from 'react-redux'; interface LinkProps { state: { @@ -33,10 +36,20 @@ const BooksBookingPage = () => { const { state } = useLocation() as LinkProps; const { bookId } = useParams(); + const navigate = useNavigate(); + const dispatch = useDispatch(); const { month, day, rentalPeriod } = calcCalendarDate(state.rentalEnd); const { mutateBookBooking } = usePostBookBooking(bookId); + const { checkBooking } = useGetCheckBooking(bookId); + + useEffect(() => { + if (!checkBooking) { + notify(dispatch, '해당 도서의 대여자는 예약할 수 없습니다.'); + navigate(`/books/${bookId}`); + } + }, []); // 예약 요청 const handleRentalButton = () => { diff --git a/frontend/src/redux/slice/notificationSlice.ts b/frontend/src/redux/slice/notificationSlice.ts index d656b564..081f39cf 100644 --- a/frontend/src/redux/slice/notificationSlice.ts +++ b/frontend/src/redux/slice/notificationSlice.ts @@ -21,6 +21,10 @@ const notificationSlice = createSlice({ initialState, reducers: { enqueueNotification: (state, action: PayloadAction) => { + const duplicatedMessage = state.messages.filter( + message => message.message === action.payload.message, + ); + if (duplicatedMessage.length) return; state.messages = [...state.messages, action.payload]; }, dequeueNotification: state => {