Skip to content

Commit

Permalink
Merge pull request #639 from jiphyeonjeon-42/develop
Browse files Browse the repository at this point in the history
build: 자잘한 버그 수정, 리렌더링 최적화 배포
  • Loading branch information
YeonSeong-Lee authored Nov 17, 2024
2 parents 3ef9710 + 5bbbbe4 commit 84d0f24
Show file tree
Hide file tree
Showing 27 changed files with 338 additions and 214 deletions.
25 changes: 20 additions & 5 deletions src/asset/css/Tags.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
line-height: 3rem;
font-size: 1.5rem;
font-weight: bold;
padding: 1rem 2rem 1rem 2rem;
padding: 1rem 2rem 1rem 1rem;
text-align: center;
margin: 1rem;
border-radius: 10px;
Expand Down Expand Up @@ -43,12 +43,18 @@
}

.button_tag-create-box {
position: flex;
line-height: 4rem;
font-size: large;
margin: 1rem;
background-color: rgba(95, 63, 54, 1);
color: rgba(255, 255, 255, 0.9);
width: 100%;
}

@media screen and (min-width: 767px) {
.button_tag-create-box {
width: 50%;
}
}

.button_tag-create-box::placeholder {
Expand All @@ -66,7 +72,6 @@
height: 100%;
min-height: 12rem;
overflow: hidden;
padding: 1.5rem 1rem;
margin: 6rem 0rem 0rem 0rem;
background-color: rgb(232, 232, 232, 0.9);
border-radius: 1rem;
Expand All @@ -83,7 +88,6 @@
height: 100%;
min-height: 12rem;
overflow: hidden;
padding: 1.5rem 1rem;
margin: -1.3rem 0rem 10rem 0rem;
background-color: rgb(232, 232, 232, 0.9);
border-radius: 1rem;
Expand Down Expand Up @@ -116,7 +120,18 @@
background-color: rgba(00, 00, 00, 0);
z-index: 1;
top: 50%;
left: 50%;
left: 0;
}

.button_tag-image-button-disabled {
display: flex;
cursor: not-allowed;
opacity: 0.4;
pointer-events: none;
}

.tooltip_cursor-message {
cursor: "help";
}

@keyframes rotateImage {
Expand Down
51 changes: 36 additions & 15 deletions src/component/book/tag/TagList.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { useState, useRef, useEffect } from "react";
import { TagType } from "../../../type/TagType";
import { useLocation } from "react-router-dom";
import { AxiosResponse, AxiosError } from "axios";
import { useApi } from "../../../hook/useApi";
import Tag from "./Tag";
import TagModal from "./TagModal";
import plusicon from "../../../asset/img/tag_plus.svg";
import Tooltip from "../../utils/Tooltip";
import { useRecoilValue } from "recoil";
import { userAtom } from "../../../atom/userAtom";
import { AxiosError, AxiosResponse } from "axios";

type TagListProps = {
tagData: TagType[];
setTagData: React.Dispatch<React.SetStateAction<TagType[]>>;
};

const TagList = ({ tagData, setTagData }: TagListProps) => {
const { isLogin } = useRecoilValue(userAtom);
const inputRef = useRef<HTMLInputElement>(null);
const location = useLocation();
const bookId = location.pathname.split("/")[2];
Expand All @@ -22,12 +25,25 @@ const TagList = ({ tagData, setTagData }: TagListProps) => {
const [lastPress, setLastPress] = useState(Date.now());
const [active, setActive] = useState<boolean>(false);
const [errorCode, setErrorCode] = useState<number | null>(null);
const errorCodeRef = useRef<number | null>(null);
const [showErrorMassege, setShowErrorMassege] = useState(false);
const { request } = useApi("post", `/tags/default`, {
const { request } = useApi("post", "tags/default", {
bookInfoId: +bookId,
content: createTag.trim().replace(/ /g, "_"),
});

useEffect(() => {
if (errorCode !== null && errorCode > 0) {
errorActive();
}
}, [errorCode]);

const onSuccess = (response: AxiosResponse) => {
const resTagdata: TagType = response.data;
setTagData(prev => [...prev, resTagdata]);
resetCreateContent();
};

const onError = (error: AxiosError) => {
setErrorCode(parseInt(error?.response?.data?.errorCode, 10));
errorActive();
Expand All @@ -42,14 +58,11 @@ const TagList = ({ tagData, setTagData }: TagListProps) => {
setTimeout(() => {
setShowErrorMassege(false);
}, 2500);
errorCodeRef.current = null;
};

const postTag = () => {
request((res: AxiosResponse) => {
const resTagdata: TagType = res.data;
setTagData(prev => [...prev, resTagdata]);
resetCreateContent();
}, onError);
request(onSuccess, onError);
};

const openModalFunc = (tagId: number) => {
Expand Down Expand Up @@ -79,15 +92,19 @@ const TagList = ({ tagData, setTagData }: TagListProps) => {
const now = Date.now();
if (now - lastPress < 300) return;
setLastPress(now);
if (!isLogin) {
setErrorCode(102);
errorCodeRef.current = 102;
}
if (createTag === "") {
setErrorCode(1);
errorCodeRef.current = 1;
} else if (createTag.length > 42) {
setErrorCode(2);
errorCodeRef.current = 2;
}

if (errorCode !== null && errorCode > 0) {
errorActive();
} else {
if (errorCodeRef.current === null) {
postTag();
}
if (inputRef.current !== null) {
Expand All @@ -97,7 +114,10 @@ const TagList = ({ tagData, setTagData }: TagListProps) => {
};

const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (errorCode !== null) setErrorCode(null);
if (errorCode !== null) {
setErrorCode(null);
errorCodeRef.current = null;
}
setCreateTag(event.target.value);
};

Expand Down Expand Up @@ -167,14 +187,15 @@ const TagList = ({ tagData, setTagData }: TagListProps) => {
onKeyUp={handleKeyPress}
/>

<Tooltip description="태그 등록">
<Tooltip
className={`${isLogin ? "" : "button_tag-image-button-disabled"}`}
description="태그 등록"
>
<img
className="button_tag-image-button"
src={plusicon}
alt="plus"
onClick={() => {
onClickCreateButton();
}}
onClick={onClickCreateButton}
/>
</Tooltip>
</button>
Expand Down
48 changes: 48 additions & 0 deletions src/component/rent/RentModalBooks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { memo } from 'react';
import { Book } from "../../type";
import BookInformationWithCover from "../utils/BookInformationWithCover";
import TextWithLabel from "../utils/TextWithLabel";
import TextareaWithLabel from "../utils/TextareaWithLabel";

interface RentModalBooksProps {
selectedBooks: Book[];
handleRemarkChange: (index: number, value: string) => void;
remarksRef: React.MutableRefObject<string[]>;
}

const RentModalBooks = ({ selectedBooks, handleRemarkChange, remarksRef }: RentModalBooksProps) => {
return (
<div className="rent-modal__books">
{selectedBooks.map((selectBook, index) => (
<div
key={selectBook.bookId}
className={`rent-modal__book-info ${index}`}
>
<BookInformationWithCover
bookCoverAlt={selectBook.title}
bookCoverImg={selectBook.image}
>
<TextWithLabel
wrapperClassName="rent-modal__book"
topLabelText="도서정보"
mainText={selectBook.title}
bottomLabelText={`청구기호 : ${selectBook.callSign}`}
/>
<TextareaWithLabel
wrapperClassName="rent-modal__remark"
topLabelText="비고"
textareaPlaceHolder="비고를 입력해주세요. (책 상태 등)"
setTextareaValue={(value: string) => handleRemarkChange(index, value)}
isTextareaFocusedOnMount={index === 0}
isVisibleBottomMessage={!remarksRef.current[index]?.length}
bottomMessageText="비고를 입력해주세요"
bottomMessageColor="red"
/>
</BookInformationWithCover>
</div>
))}
</div>
);
};

export default memo(RentModalBooks);
72 changes: 20 additions & 52 deletions src/component/rent/RentModalConfirm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { FormEventHandler, useState } from "react";
import { FormEventHandler, useCallback, useState, useRef } from "react";
import Button from "../utils/Button";
import BookInformationWithCover from "../utils/BookInformationWithCover";
import TextWithLabel from "../utils/TextWithLabel";
import TextareaWithLabel from "../utils/TextareaWithLabel";
import { usePostLendingsMultiple } from "../../api/lendings/usePostLendingsMultiple";
import { Book, User } from "../../type";
import "../../asset/css/RentModalConfirm.css";
import { userRoleStatusEnum } from "~/constant/status";
import RentModalBooks from "./RentModalBooks";

type Props = {
selectedUser: User;
Expand All @@ -23,7 +21,8 @@ const RentModalConfirm = ({
setSelectedBooks,
closeModal,
}: Props) => {
const [remarks, setRemarks] = useState<string[]>([]);
const remarksRef = useRef<string[]>([]);
const [isRentable, setIsRentable] = useState(false);

const { requestLending } = usePostLendingsMultiple({
selectedBooks,
Expand All @@ -35,20 +34,19 @@ const RentModalConfirm = ({

const postData: FormEventHandler = e => {
e.preventDefault();
requestLending(remarks);
};

const isRentable =
selectedBooks.length > 1
? remarks.slice(0, selectedBooks.length).every(remark => remark.length > 0)
: remarks[0]?.length > 0;

const handleRemarkChange = (index: number, value: string) => {
const updatedRemarks = [...remarks];
updatedRemarks[index] = value;
setRemarks(updatedRemarks);
requestLending(remarksRef.current);
};

const handleRemarkChange = useCallback((index: number, value: string) => {
remarksRef.current = [...remarksRef.current];
remarksRef.current[index] = value;

const newIsRentable = selectedBooks.length > 1
? remarksRef.current.slice(0, selectedBooks.length).every(remark => remark?.length > 0)
: remarksRef.current[0]?.length > 0;
setIsRentable(newIsRentable);
}, [selectedBooks.length]);

return (
<form className="rent-modal">
<div className="rent-modal__user">
Expand All @@ -64,41 +62,11 @@ const RentModalConfirm = ({
</div>
)}
</div>
<div className="rent-modal__books">
{selectedBooks.map((selectBook, index) => {
const isFirst = index === 0;

return (
<div
key={selectBook.bookId}
className={`rent-modal__book-info ${index}`}
>
<BookInformationWithCover
bookCoverAlt={selectBook.title}
bookCoverImg={selectBook.image}
>
<TextWithLabel
wrapperClassName="rent-modal__book"
topLabelText="도서정보"
mainText={selectBook.title}
bottomLabelText={`청구기호 : ${selectBook.callSign}`}
/>
<TextareaWithLabel
wrapperClassName="rent-modal__remark"
topLabelText="비고"
textareaPlaceHolder="비고를 입력해주세요. (책 상태 등)"
textareaValue={remarks[index]}
setTextareaValue={(value: string) => handleRemarkChange(index, value)}
isTextareaFocusedOnMount={index === 0}
isVisibleBottomMessage={!remarks[index]?.length}
bottomMessageText="비고를 입력해주세요"
bottomMessageColor="red"
/>
</BookInformationWithCover>
</div>
);
})}
</div>
<RentModalBooks
selectedBooks={selectedBooks}
handleRemarkChange={handleRemarkChange}
remarksRef={remarksRef}
/>
<div className="rent-modal__buttons">
<Button
type="submit"
Expand Down
18 changes: 11 additions & 7 deletions src/component/reservedloan/ReservedModalContents.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FormEventHandler, useState } from "react";
import { FormEventHandler, useRef, useState } from "react";
import { usePostLendings } from "../../api/lendings/usePostLendings";
import { usePatchReservationsCancel } from "../../api/reservations/usePatchReservationsCancel";
import Button from "../utils/Button";
Expand All @@ -16,7 +16,8 @@ type Props = {
};

const ReservedModalContents = ({ reservedInfo, closeModal }: Props) => {
const [remark, setRemark] = useState("");
const remarkRef = useRef<string>('');
const [isRentable, setIsRentable] = useState(false);

const { setReservationId: cancelReservation } = usePatchReservationsCancel();

Expand All @@ -27,13 +28,17 @@ const ReservedModalContents = ({ reservedInfo, closeModal }: Props) => {
closeModal,
});

const setTextareaValue = (value: string) => {
remarkRef.current = value;
setIsRentable(Boolean(isRent && isValidString(value)));
};

const postRent: FormEventHandler = e => {
e.preventDefault();
requestLending(remark);
requestLending(remarkRef.current || "");
};

const isRent = !reservedInfo.status && reservedInfo?.endAt;
const isRentable = isRent && isValidString(remark);
const isAvaliableReservation = !reservedInfo.status && !reservedInfo?.endAt;

return (
Expand Down Expand Up @@ -67,9 +72,8 @@ const ReservedModalContents = ({ reservedInfo, closeModal }: Props) => {
wrapperClassName="reserved-modal__remark"
topLabelText="비고"
textareaPlaceHolder="비고를 입력해주세요. (책 상태 등)"
textareaValue={remark}
setTextareaValue={setRemark}
isVisibleBottomMessage={!remark.length}
setTextareaValue={setTextareaValue}
isVisibleBottomMessage={!remarkRef.current}
bottomMessageText="비고를 입력해주세요"
bottomMessageColor="red"
/>
Expand Down
Loading

0 comments on commit 84d0f24

Please sign in to comment.