From 174794fff56affb805c3863ef6c226c30b627b17 Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Sun, 13 Aug 2023 05:27:27 +0900 Subject: [PATCH 001/208] =?UTF-8?q?[FE]=20FEAT=20:=20invitation=5Fcode=5Fm?= =?UTF-8?q?odal=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/data/maps.ts | 5 + .../CabinetInfoArea.container.tsx | 11 +- .../CabinetInfoArea/CabinetInfoArea.tsx | 15 +- .../InvitationCodeModal.container.tsx | 145 ++++++++++++++++ .../InvitationCodeModal.tsx | 160 ++++++++++++++++++ 5 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx create mode 100644 frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.tsx diff --git a/frontend/src/assets/data/maps.ts b/frontend/src/assets/data/maps.ts index 7487ec26a..788ebcf23 100644 --- a/frontend/src/assets/data/maps.ts +++ b/frontend/src/assets/data/maps.ts @@ -131,6 +131,11 @@ export const modalPropsMap = { title: "패널티 안내", confirmMessage: "오늘 하루동안 보지않기", }, + MODAL_INVITATION_CODE: { + type: "confirm", + title: "초대 코드", + confirmMessage: "대여하기", + }, }; export const cabinetFilterMap = { diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx index 02df2ba0d..bf4d1177f 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx @@ -46,6 +46,7 @@ export interface ICurrentModalStateInfo { returnModal: boolean; memoModal: boolean; passwordCheckModal: boolean; + invitationCodeModal: boolean; } export interface IAdminCurrentModalStateInfo { @@ -66,7 +67,8 @@ export type TModalState = | "unavailableModal" | "returnModal" | "memoModal" - | "passwordCheckModal"; + | "passwordCheckModal" + | "invitationCodeModal"; export type TAdminModalState = "returnModal" | "statusModal" | "clubLentModal"; @@ -151,6 +153,7 @@ const CabinetInfoAreaContainer = (): JSX.Element => { returnModal: false, memoModal: false, passwordCheckModal: false, + invitationCodeModal: false, }); const [adminModal, setAdminModal] = useState({ returnModal: false, @@ -204,6 +207,12 @@ const CabinetInfoAreaContainer = (): JSX.Element => { targetCabinetInfo.lents.length === 1 ) { modalName = "passwordCheckModal"; + } else if ( + modalName === "lentModal" && + cabinetViewData?.lentsLength && + cabinetViewData.lentsLength >= 1 + ) { + modalName = "invitationCodeModal"; } setUserModal({ ...userModal, diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index 8011387c9..5246103c6 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -20,6 +20,7 @@ import { import cabiLogo from "@/assets/images/logo.svg"; import CabinetStatus from "@/types/enum/cabinet.status.enum"; import CabinetType from "@/types/enum/cabinet.type.enum"; +import InvitationCodeModalContainer from "../Modals/InvitationCodeModal/InvitationCodeModal.container"; const CabinetInfoArea: React.FC<{ selectedCabinetInfo: ISelectedCabinetInfo | null; @@ -90,7 +91,14 @@ const CabinetInfoArea: React.FC<{ ) : ( <> openModal("lentModal")} + onClick={() => + openModal( + selectedCabinetInfo?.lentsLength && + selectedCabinetInfo.lentsLength >= 1 + ? "invitationCodeModal" + : "lentModal" + ) + } text="대여" theme="fill" disabled={!isAvailable || selectedCabinetInfo.lentType === "CLUB"} @@ -134,6 +142,11 @@ const CabinetInfoArea: React.FC<{ onClose={() => closeModal("passwordCheckModal")} /> )} + {userModal.invitationCodeModal && ( + closeModal("invitationCodeModal")} + /> + )} ); }; diff --git a/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx b/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx new file mode 100644 index 000000000..21412ff8b --- /dev/null +++ b/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx @@ -0,0 +1,145 @@ +import React, { useState } from "react"; +import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; +import { + currentCabinetIdState, + isCurrentSectionRenderState, + myCabinetInfoState, + targetCabinetInfoState, + userState, +} from "@/recoil/atoms"; +import InvitationCodeModal from "@/components/Modals/InvitationCodeModal/InvitationCodeModal"; +import { IModalContents } from "@/components/Modals/Modal"; +import ModalPortal from "@/components/Modals/ModalPortal"; +import PasswordContainer from "@/components/Modals/PasswordCheckModal/PasswordContainer"; +import { + FailResponseModal, + SuccessResponseModal, +} from "@/components/Modals/ResponseModal/ResponseModal"; +import { modalPropsMap } from "@/assets/data/maps"; +import checkIcon from "@/assets/images/checkIcon.svg"; +import { MyCabinetInfoResponseDto } from "@/types/dto/cabinet.dto"; +import { + axiosCabinetById, + axiosLentId, + axiosMyLentInfo, +} from "@/api/axios/axios.custom"; +import PasswordCheckModal from "../PasswordCheckModal/PasswordCheckModal"; + +const InvitationCodeModalContainer: React.FC<{ + onClose: () => void; +}> = (props) => { + const [showResponseModal, setShowResponseModal] = useState(false); + const [hasErrorOnResponse, setHasErrorOnResponse] = useState(false); + const [wrongCodeCounts, setWrongCodeCounts] = useState(0); + const currentCabinetId = useRecoilValue(currentCabinetIdState); + const [modalTitle, setModalTitle] = useState(""); + const [code, setCode] = useState(""); + const [myInfo, setMyInfo] = useRecoilState(userState); + const setTargetCabinetInfo = useSetRecoilState(targetCabinetInfoState); + const setIsCurrentSectionRender = useSetRecoilState( + isCurrentSectionRenderState + ); + const setMyLentInfo = + useSetRecoilState(myCabinetInfoState); + + const onChange = (e: React.ChangeEvent) => { + const regex = /^[0-9]{0,4}$/; + if (!regex.test(e.target.value)) { + e.target.value = code; + return; + } + setCode(e.target.value); + }; + + const tryLentRequest = async () => { + try { + await axiosLentId(currentCabinetId); + setMyInfo({ ...myInfo, cabinetId: currentCabinetId }); + setIsCurrentSectionRender(true); + setModalTitle("대여가 완료되었습니다"); + + try { + const { data } = await axiosCabinetById(currentCabinetId); + setTargetCabinetInfo(data); + } catch (error) { + throw error; + } + + try { + const { data: myLentInfo } = await axiosMyLentInfo(); + setMyLentInfo(myLentInfo); + } catch (error) { + throw error; + } + } catch (error: any) { + setModalTitle(error.response.data.message); + setHasErrorOnResponse(true); + throw error; + } finally { + setShowResponseModal(true); + } + }; + + const onSendCode = async () => { + try { + //초대코드 받아오는 api 넣어야 함. + const sharedCode = "4242"; + + if (code === sharedCode) { + await tryLentRequest(); + } else { + setWrongCodeCounts((prevCounts) => prevCounts + 1); + setModalTitle("일치하지 않는 초대 코드입니다."); + setHasErrorOnResponse(true); + setShowResponseModal(true); + } + } catch (error: any) { + setModalTitle(error.response.data.message); + setHasErrorOnResponse(true); + setShowResponseModal(true); + } + }; + + const RentBtnDisabled = wrongCodeCounts >= 3; + + const InvititaionCodeModalContents: IModalContents = { + type: "hasProceedBtn", + icon: checkIcon, + title: modalPropsMap["MODAL_INVITATION_CODE"].title, + detail: `공유 사물함 입장을 위한 + 초대 코드를 입력해 주세요. + 3번 이상 일치하지 않을 시 입장이 제한됩니다.`, + proceedBtnText: modalPropsMap["MODAL_INVITATION_CODE"].confirmMessage, + onClickProceed: onSendCode, + renderAdditionalComponent: () => ( + + ), + closeModal: props.onClose, + }; + + return ( + + {!showResponseModal && ( + + )} + {showResponseModal && + (hasErrorOnResponse ? ( + + ) : ( + + ))} + + ); +}; + +export default InvitationCodeModalContainer; diff --git a/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.tsx b/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.tsx new file mode 100644 index 000000000..65a837ec5 --- /dev/null +++ b/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.tsx @@ -0,0 +1,160 @@ +import React, { useState } from "react"; +import styled, { css } from "styled-components"; +import Button from "@/components/Common/Button"; +import { IModalContents } from "@/components/Modals/Modal"; +import useMultiSelect from "@/hooks/useMultiSelect"; + +const InvitationCodeModal: React.FC<{ + modalContents: IModalContents; + code: string; + RentBtnDisabled: boolean; +}> = ({ modalContents, code, RentBtnDisabled }) => { + const { + type, + icon, + iconScaleEffect, + title, + detail, + renderAdditionalComponent, + proceedBtnText, + onClickProceed, + cancleBtnText, + closeModal, + } = modalContents; + const { isMultiSelect, closeMultiSelectMode } = useMultiSelect(); + + return ( + <> + { + closeModal(e); + if (isMultiSelect) { + closeMultiSelectMode(); + } + }} + /> + + {icon && ( + + )} + {title} + {detail && ( + + )} + {renderAdditionalComponent && renderAdditionalComponent()} + + ); @@ -102,13 +80,15 @@ const WrapperStyled = styled.div` `; const TitleContainerStyled = styled.div` - width: 600px; + width: 70%; display: flex; flex-direction: column; justify-content: center; - align-items: center; - padding-bottom: 70px; - border-bottom: 2px solid var(--main-color); + align-items: flex-start; + border-bottom: 2px solid #d9d9d9; + margin-bottom: 100px; + color: var(--main-color); + font-weight: 700; .logo { width: 35px; height: 35px; @@ -120,40 +100,34 @@ const TitleContainerStyled = styled.div` margin-bottom: 20px; } .title > span { - font-weight: 700; + color: black; } +`; + +const WrapSectionStyled = styled.div` + width: 70%; + max-width: 1500px; .subtitle { - font-size: 1.5rem; - color: var(--lightpurple-color); + font-size: 2.5rem; + line-height: 1.4; + text-align: left; + font-weight: bold; } `; const InfoSectionStyled = styled.section` display: flex; - justify-content: space-between; margin-top: 40px; - width: 90%; + margin-bottom: 60px; + width: 100%; max-width: 1500px; .article { - width: 100%; + //width: 100%; display: flex; flex-direction: column; - align-items: center; + align-items: flex-start; margin-bottom: 70px; } - .article > div { - width: 58px; - height: 58px; - display: flex; - justify-content: center; - align-items: center; - background-color: rgba(113, 46, 255, 0.1); - border-radius: 50%; - } - .article > div > img { - width: 24px; - height: 24px; - } .article > h3 { min-width: 200px; text-align: center; @@ -168,7 +142,8 @@ const InfoSectionStyled = styled.section` text-align: center; } .redColor { - color: var(--expired); + color: #ef8172; + margin: 20px 0 0 140px; } .article > p > span { font-weight: 700; diff --git a/frontend/src/components/Home/tmp.tsx b/frontend/src/components/Home/tmp.tsx new file mode 100644 index 000000000..789e51797 --- /dev/null +++ b/frontend/src/components/Home/tmp.tsx @@ -0,0 +1,203 @@ +import styled from "styled-components"; +import MaunalContentBox from "@/components/Home/ManualContentBox"; + +const ServiceManual = ({ + lentStartHandler, +}: { + lentStartHandler: React.MouseEventHandler; +}) => { + return ( + + +
+ +
+

+ 42Cabi 이용 안내서 +

+
+ +

+ 가능성의 확장 +
+ 개인, 공유, 동아리 사물함. +

+ +
+ +
+ +
+

+ 1인이 1개의 사물함을 사용합니다. +
+ 최대 + {import.meta.env.VITE_PRIVATE_LENT_PERIOD}일간 + {" "} + 대여할 수 있습니다. +
+ 연체 시 연체되는{" "} + 일 수만큼 페널티가 부과됩니다. +

+
+
+ +
+ +
+

공유 사물함

+

+ 1개의 사물함을 최대{" "} + {import.meta.env.VITE_SHARE_MAX_USER}인이 사용합니다. +
+ {import.meta.env.VITE_SHARE_LENT_PERIOD}일간 대여할 + 수 있습니다. +
+ 사물함 제목과 메모는 대여자들끼리 공유됩니다. +
+ 대여 후{" "} + + {import.meta.env.VITE_SHARE_EARLY_RETURN_PERIOD}시간 + {" "} + 내 반납 시, +
+ {import.meta.env.VITE_SHARE_EARLY_RETURN_PENALTY}시간 동안 공유 + 사물함 대여가 + 불가능합니다. +
+ 연체 시 연체되는{" "} + 일 수만큼 페널티가 부과됩니다. +

+
+
+ +
+ +
+

동아리 사물함

+

+ 모집 기간에만 대여할 수 있습니다. +
+ 새로운 기수가 들어올 때 갱신됩니다. +
+ 사물함 대여는{" "} + + 슬랙 캐비닛 채널 + + 로 문의주세요. +
+ 상세 페이지가 제공되지 않습니다. +
+ 비밀번호는 동아리 내에서 공유하여 이용하세요. +

+
+
+

+ 공정한 대여를 위한 +
+ 새로운 사물함 상태. +

+
+ +
+ ); +}; + +const WrapperStyled = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 70px 0; +`; + +const TitleContainerStyled = styled.div` + width: 600px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border-bottom: 2px solid #d9d9d9; + .logo { + width: 35px; + height: 35px; + margin-bottom: 20px; + } + .title { + font-size: 2.5rem; + letter-spacing: -0.02rem; + margin-bottom: 20px; + } + .title > span { + font-weight: 700; + } +`; + +const WrapSectionStyled = styled.div` + width: 70%; + max-width: 1500px; + .subtitle { + font-size: 2.5rem; + line-height: 1.4; + text-align: left; + font-weight: bold; + } +`; + +const InfoSectionStyled = styled.section` + display: flex; + justify-content: space-between; + margin-top: 40px; + width: 100%; + max-width: 1500px; + .article { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: 70px; + } + .article > div { + /* width: 58px; + height: 58px; */ + //display: flex; + //justify-content: center; + //align-items: center; + //background-color: rgba(113, 46, 255, 0.1); + //border-radius: 50%; + } + /* .article > div > img { + width: 24px; + height: 24px; + } */ + .article > h3 { + min-width: 200px; + text-align: center; + font-size: 1.5rem; + margin: 15px 0; + font-weight: 700; + } + .article > p { + font-size: 1.125rem; + line-height: 1.6; + letter-spacing: -0.02rem; + text-align: center; + } + .redColor { + color: var(--expired); + } + .article > p > span { + font-weight: 700; + } +`; + +const AtagStyled = styled.a` + text-decoration: underline; + font-weight: 700; +`; + +export default ServiceManual; diff --git a/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx b/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx index 7855084b5..8f3c8a4c1 100644 --- a/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx +++ b/frontend/src/components/Modals/InvitationCodeModal/InvitationCodeModal.container.tsx @@ -112,31 +112,6 @@ const InvitationCodeModalContainer: React.FC<{ } }; - const onSendCode = async () => { - try { - //초대코드 받아오는 api 넣어야 함. - const sharedCode = "4242"; - - if (code === sharedCode) { - await tryLentRequest(); - } else { - const updatedCounts = { - ...sharedWrongCodeCounts, - [String(props.cabinetId)]: - (sharedWrongCodeCounts[String(props.cabinetId)] || 0) + 1, - }; - saveSharedWrongCodeCounts(updatedCounts); - setModalTitle("일치하지 않는 초대 코드입니다."); - setHasErrorOnResponse(true); - setShowResponseModal(true); - } - } catch (error: any) { - setModalTitle(error.response.data.message); - setHasErrorOnResponse(true); - setShowResponseModal(true); - } - }; - const InvititaionCodeModalContents: IModalContents = { type: "hasProceedBtn", icon: checkIcon, diff --git a/frontend/src/components/Modals/ManualModal/ManualModal.tsx b/frontend/src/components/Modals/ManualModal/ManualModal.tsx new file mode 100644 index 000000000..3b1f092f1 --- /dev/null +++ b/frontend/src/components/Modals/ManualModal/ManualModal.tsx @@ -0,0 +1,123 @@ +import React, { useState } from "react"; +import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; +import { + currentCabinetIdState, + isCurrentSectionRenderState, + myCabinetInfoState, + targetCabinetInfoState, + userState, +} from "@/recoil/atoms"; +import Modal, { IModalContents } from "@/components/Modals/Modal"; +import ModalPortal from "@/components/Modals/ModalPortal"; +import { + FailResponseModal, + SuccessResponseModal, +} from "@/components/Modals/ResponseModal/ResponseModal"; +import { modalPropsMap } from "@/assets/data/maps"; +import checkIcon from "@/assets/images/checkIcon.svg"; +import { MyCabinetInfoResponseDto } from "@/types/dto/cabinet.dto"; +import CabinetStatus from "@/types/enum/cabinet.status.enum"; +import { + axiosCabinetById, + axiosLentId, + axiosLentShareId, + axiosMyLentInfo, +} from "@/api/axios/axios.custom"; +import { getExpireDateString } from "@/utils/dateUtils"; + +const ManualModal: React.FC<{ + lentType: string; + closeModal: React.MouseEventHandler; +}> = (props) => { + const [showResponseModal, setShowResponseModal] = useState(false); + const [hasErrorOnResponse, setHasErrorOnResponse] = useState(false); + const [modalTitle, setModalTitle] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const currentCabinetId = useRecoilValue(currentCabinetIdState); + const [myInfo, setMyInfo] = useRecoilState(userState); + const setMyLentInfo = + useSetRecoilState(myCabinetInfoState); + const [targetCabinetInfo, setTargetCabinetInfo] = useRecoilState( + targetCabinetInfoState + ); + const setIsCurrentSectionRender = useSetRecoilState( + isCurrentSectionRenderState + ); + + const formattedExpireDate = getExpireDateString(props.lentType); + const privateLentDetail = `대여기간은 ${formattedExpireDate} 23:59까지 입니다. + 귀중품 분실 및 메모 내용의 유출에 책임지지 않습니다.`; + const shareLentDetail = `대여 후 ${ + 10 + // import.meta.env.VITE_SHARE_LENT_COUNTDOWN // TODO: .env 에 등록하기 + }분 이내에 + 공유 인원 (2인~4인) 이 충족되지 않으면, + 공유 사물함의 대여가 취소됩니다. + “메모 내용”은 공유 인원끼리 공유됩니다. + 귀중품 분실 및 메모 내용의 유출에 책임지지 않습니다.`; + const tryLentRequest = async (e: React.MouseEvent) => { + setIsLoading(true); + try { + if (props.lentType == "SHARE") + await axiosLentShareId(currentCabinetId, "0"); + else await axiosLentId(currentCabinetId); + //userCabinetId 세팅 + setMyInfo({ ...myInfo, cabinetId: currentCabinetId }); + setIsCurrentSectionRender(true); + if (props.lentType == "SHARE") + setModalTitle("공유 사물함 대기열에 입장하였습니다"); + else setModalTitle("대여가 완료되었습니다"); + // 캐비닛 상세정보 바꾸는 곳 + try { + const { data } = await axiosCabinetById(currentCabinetId); + setTargetCabinetInfo(data); + } catch (error) { + throw error; + } + // 내 대여정보 바꾸는 곳 + try { + const { data: myLentInfo } = await axiosMyLentInfo(); + setMyLentInfo(myLentInfo); + } catch (error) { + throw error; + } + } catch (error: any) { + setModalTitle(error.response.data.message); + setHasErrorOnResponse(true); + } finally { + setIsLoading(false); + setShowResponseModal(true); + } + }; + + const lentModalContents: IModalContents = { + type: "hasProceedBtn", + icon: checkIcon, + title: modalPropsMap[CabinetStatus.AVAILABLE].title, + detail: props.lentType === "PRIVATE" ? privateLentDetail : shareLentDetail, + proceedBtnText: modalPropsMap[CabinetStatus.AVAILABLE].confirmMessage, + onClickProceed: tryLentRequest, + closeModal: props.closeModal, + isLoading: isLoading, + }; + + return ( + + {!showResponseModal && } + {showResponseModal && + (hasErrorOnResponse ? ( + + ) : ( + + ))} + + ); +}; + +export default ManualModal; diff --git a/frontend/src/components/TopNav/TopNav.tsx b/frontend/src/components/TopNav/TopNav.tsx index 28b6fc308..46033e80b 100644 --- a/frontend/src/components/TopNav/TopNav.tsx +++ b/frontend/src/components/TopNav/TopNav.tsx @@ -96,9 +96,10 @@ const TopNavContainerStyled = styled.nav` display: flex; justify-content: space-between; align-items: center; - background-color: var(--main-color); + background-color: white; + border-bottom: 1px solid #bcbcbc; padding: 0 28px; - color: var(--white); + color: var(--gray-color); z-index: 10; `; From e43ba3709da693bc20e2fe27367cd49f4bab514d Mon Sep 17 00:00:00 2001 From: ldw Date: Sat, 2 Sep 2023 23:24:18 +0900 Subject: [PATCH 186/208] =?UTF-8?q?[BE]=20FEAT=20:=20redis=EC=97=90=20?= =?UTF-8?q?=EC=9D=B4=EC=A0=84=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=97=86?= =?UTF-8?q?=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20DB=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=B0=BE=EC=95=84=EC=98=A4=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lent/repository/LentOptionalFetcher.java | 6 ++++++ .../ftclub/cabinet/lent/repository/LentRedis.java | 2 +- .../cabinet/lent/repository/LentRepository.java | 9 +++++++++ .../lent/service/LentFacadeServiceImpl.java | 15 +++++++++++++-- .../org/ftclub/cabinet/mapper/CabinetMapper.java | 1 - 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java index e14f7a527..17a9874c0 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentOptionalFetcher.java @@ -2,6 +2,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.cabinet.domain.Cabinet; @@ -238,4 +239,9 @@ public List findAllActiveLentHistoriesByUserId(Long userId) { log.debug("Called findAllActiveLentHistoriesByUserId: {}", userId); return lentRepository.findAllActiveLentHistoriesByUserId(userId); } + + public Optional findPreviousLentHistoryByCabinetId(Long cabinetId) { + log.debug("Called findPreviousLentUserNameByCabinetId: {}", cabinetId); + return lentRepository.findFirstByCabinetIdAndEndedAtIsNotNullOrderByEndedAtDesc(cabinetId); + } } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java index 27740f38c..eae344e1d 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java @@ -173,7 +173,7 @@ public void setPreviousUser(String cabinetId, String userName) { previousUserRedisTemplate.set(cabinetId + PREVIOUS_USER_SUFFIX, userName); } - public String getPreviousUser(String cabinetId) { + public String getPreviousUserName(String cabinetId) { log.debug("Called getPreviousUser: {}", cabinetId); return previousUserRedisTemplate.get(cabinetId + PREVIOUS_USER_SUFFIX); } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRepository.java b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRepository.java index bd632ba99..bbda21a0b 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRepository.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRepository.java @@ -77,6 +77,14 @@ List findByUserIdAndEndedAtNotNull(@Param("userId") Long userId, */ List findByCabinetId(@Param("cabinetId") Long cabinetId, Pageable pageable); + /*** + * 사물함을 기준으로 가장 최근에 반납한 {@link LentHistory} 를 가져옵니다. + * @param cabinetId 찾으려는 cabinet id + * @return 반납한 {@link LentHistory}의 {@link Optional} + */ + Optional findFirstByCabinetIdAndEndedAtIsNotNullOrderByEndedAtDesc( + @Param("cabinetId") Long cabinetId); + /** * 유저가 빌리고 있는 사물함의 개수를 가져옵니다. * @@ -195,4 +203,5 @@ Integer countReturnByTimeDuration(@Param("startDate") LocalDateTime startDate, + "IN (SELECT lh2.cabinetId " + "FROM LentHistory lh2 WHERE lh2.userId = :userId AND lh2.endedAt IS NULL)") List findAllActiveLentHistoriesByUserId(@Param("userId") Long userId); + } \ No newline at end of file diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentFacadeServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentFacadeServiceImpl.java index 4d2f6ec51..3128fc9c8 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentFacadeServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentFacadeServiceImpl.java @@ -1,6 +1,7 @@ package org.ftclub.cabinet.lent.service; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import javax.transaction.Transactional; import lombok.AllArgsConstructor; @@ -156,9 +157,19 @@ public MyCabinetResponseDto getMyLentInfo(@UserSession UserSessionDto user) { if (myCabinet == null) { // 대여 기록이 없거나 대여 대기 중인 경우 return getMyLentInfoFromRedis(user); } - List lentDtoList = getLentDtoList(myCabinet.getCabinetId()); + Long cabinetId = myCabinet.getCabinetId(); + List lentDtoList = getLentDtoList(cabinetId); + String previousUserName = lentRedis.getPreviousUserName( + myCabinet.getCabinetId().toString()); + if (previousUserName == null) { + Optional previousLentHistory = lentOptionalFetcher.findPreviousLentHistoryByCabinetId( + cabinetId); + if (previousLentHistory.isPresent()) { + previousUserName = previousLentHistory.get().getUser().getName(); + } + } return cabinetMapper.toMyCabinetResponseDto(myCabinet, lentDtoList, - null, null, lentRedis.getPreviousUser(myCabinet.getCabinetId().toString())); + null, null, previousUserName); } @Override diff --git a/backend/src/main/java/org/ftclub/cabinet/mapper/CabinetMapper.java b/backend/src/main/java/org/ftclub/cabinet/mapper/CabinetMapper.java index 8e6d84a16..afb039b2a 100644 --- a/backend/src/main/java/org/ftclub/cabinet/mapper/CabinetMapper.java +++ b/backend/src/main/java/org/ftclub/cabinet/mapper/CabinetMapper.java @@ -87,7 +87,6 @@ UserCabinetPaginationDto toUserCabinetPaginationDto(List result, @Mapping(target = "location", source = "cabinet.cabinetPlace.location") @Mapping(target = "shareCode", source = "sessionShareCode") - @Mapping(target = "sessionExpiredAt", source = "sessionExpiredAt") MyCabinetResponseDto toMyCabinetResponseDto(Cabinet cabinet, List lents, String sessionShareCode, LocalDateTime sessionExpiredAt, String previousUserName); From 92160774bc8b477876bdb051ef74d1dd097128a1 Mon Sep 17 00:00:00 2001 From: ldw Date: Sun, 3 Sep 2023 01:57:48 +0900 Subject: [PATCH 187/208] =?UTF-8?q?[BE]=20FEAT=20:=20=EC=96=B4=EB=93=9C?= =?UTF-8?q?=EB=AF=BC=EC=97=90=EC=84=9C=20=EC=82=AC=EB=AC=BC=ED=95=A8=20?= =?UTF-8?q?=EB=B0=98=EB=82=A9=20=EC=8B=9C=ED=82=AC=20=EC=8B=9C=20=EC=9D=B4?= =?UTF-8?q?=EC=A0=84=20=EC=82=AC=EC=9A=A9=EC=9E=90=20redis=EC=97=90=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/ftclub/cabinet/lent/service/LentServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java index aa3c11fd3..756a8ada2 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java @@ -197,6 +197,8 @@ private List returnCabinetByCabinetId(Long cabinetId) { // log.info("cabinet status {}",cabinet.getStatus()); cabinet.writeMemo(""); cabinet.writeTitle(""); + lentRedis.setPreviousUser(cabinet.getCabinetId().toString(), + lentHistories.get(0).getUser().getName()); return lentHistories; } @@ -213,6 +215,8 @@ private LentHistory returnCabinetByUserId(Long userId) { cabinet.writeMemo(""); cabinet.writeTitle(""); } + lentRedis.setPreviousUser(cabinet.getCabinetId().toString(), + lentHistory.getUser().getName()); return lentHistory; } From a1a099a54081a116ee65163a0bdde3061ea99992 Mon Sep 17 00:00:00 2001 From: ldw Date: Sun, 3 Sep 2023 03:00:08 +0900 Subject: [PATCH 188/208] =?UTF-8?q?[BE]=20FEAT=20:=20admin=20page=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=97=B0=EC=B2=B4=EB=90=9C=20=EC=82=AC=EB=AC=BC?= =?UTF-8?q?=ED=95=A8=EC=9D=84=20=EB=B0=98=EB=82=A9=20=EC=8B=9C=ED=82=A4?= =?UTF-8?q?=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20penalty=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/ftclub/cabinet/lent/service/LentServiceImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java index 756a8ada2..989f001c9 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/service/LentServiceImpl.java @@ -191,8 +191,11 @@ private List returnCabinetByCabinetId(Long cabinetId) { log.debug("Called returnCabinetByCabinetId: {}", cabinetId); Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(cabinetId); List lentHistories = lentOptionalFetcher.findAllActiveLentByCabinetId( - cabinetId); + cabinetId); // todo : 현재 returnCabinetByCabinetId는 개인사물함 반납에 대해서만 사용되고 있기 때문에 lentHistory에 대한 list로 받을 필요가 없음 - 추후 추가 확인 후 로직 수정 필요 lentHistories.forEach(lentHistory -> lentHistory.endLent(LocalDateTime.now())); + userService.banUser(lentHistories.get(0).getUserId(), cabinet.getLentType(), + lentHistories.get(0).getStartedAt(), + lentHistories.get(0).getEndedAt(), lentHistories.get(0).getExpiredAt()); cabinet.specifyStatusByUserCount(0); // policy로 빼는게..? // log.info("cabinet status {}",cabinet.getStatus()); cabinet.writeMemo(""); @@ -204,12 +207,13 @@ private List returnCabinetByCabinetId(Long cabinetId) { private LentHistory returnCabinetByUserId(Long userId) { log.debug("Called returnCabinet: {}", userId); -// userOptionalFetcher.getUser(userId); LentHistory lentHistory = lentOptionalFetcher.getActiveLentHistoryWithUserIdForUpdate( userId); Cabinet cabinet = cabinetOptionalFetcher.getCabinetForUpdate(lentHistory.getCabinetId()); int activeLentCount = lentRepository.countCabinetActiveLent(lentHistory.getCabinetId()); lentHistory.endLent(LocalDateTime.now()); + userService.banUser(userId, cabinet.getLentType(), lentHistory.getStartedAt(), + lentHistory.getEndedAt(), lentHistory.getExpiredAt()); cabinet.specifyStatusByUserCount(activeLentCount - 1); // policy로 빠질만한 부분인듯? if (activeLentCount - 1 == 0) { cabinet.writeMemo(""); From 5e1c0fc38cfa83183bb8f9ed8301675d5d143251 Mon Sep 17 00:00:00 2001 From: jusohn Date: Sun, 3 Sep 2023 15:29:38 +0900 Subject: [PATCH 189/208] =?UTF-8?q?[FE]=20FEAT:=20=EA=B3=B5=EC=9C=A0?= =?UTF-8?q?=EC=82=AC=EB=AC=BC=ED=95=A8=EC=9D=84=20=EB=8B=A8=EB=8F=85?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=82=AC=EC=9A=A9=20=EC=A4=91=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0,=20=EC=97=B0=EC=9E=A5=EA=B6=8C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20Hover=20?= =?UTF-8?q?=EC=8B=9C=20=EC=95=88=EB=82=B4=20=EB=AC=B8=EA=B5=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CabinetInfoArea/CabinetInfoArea.tsx | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index 2b2e4e6d8..30cb26558 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -17,6 +17,7 @@ import { cabinetLabelColorMap, cabinetStatusColorMap, } from "@/assets/data/maps"; +import alertImg from "@/assets/images/cautionSign.svg"; import cabiLogo from "@/assets/images/logo.svg"; import CabinetStatus from "@/types/enum/cabinet.status.enum"; import CabinetType from "@/types/enum/cabinet.type.enum"; @@ -86,7 +87,6 @@ const CabinetInfoArea: React.FC<{ }} text="대기열 취소" theme="fill" - //disabled={timeOver} /> )} + + + 공유사물함을 단독으로 이용 시,
+ 연장권을 사용할 수 없습니다. +
{userModal.unavailableModal && ( ` + position: absolute; + top: 50%; + width: 270px; + height: 80px; + padding: 10px; + background-color: rgba(73, 73, 73, 0.99); + border-radius: 10px; + box-shadow: 4px 4px 20px 0px rgba(0, 0, 0, 0.5); + font-size: 14px; + text-align: center; + color: white; + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: center; + opacity: ${(props) => (props.canUseExtendTicket ? "1" : "0")}; +`; + +const AlertImgStyled = styled.img` + width: 20px; + height: 20px; + filter: invert(99%) sepia(100%) saturate(3%) hue-rotate(32deg) + brightness(104%) contrast(100%); +`; + +const CabinetInfoButtonsContainerStyled = styled.div<{ + canUseExtendTicket?: boolean; +}>` display: flex; flex-direction: column; justify-content: flex-start; @@ -341,6 +383,9 @@ const CabinetInfoButtonsContainerStyled = styled.div` max-height: 320px; margin: 3vh 0; width: 100%; + &:hover ${HoverBox} { + opacity: ${(props) => (props.canUseExtendTicket ? "0" : "1")}; + } `; const CabinetLentDateInfoStyled = styled.div<{ textColor: string }>` From e523446e89afc5deb31e778a58bf93ea2ef1f28b Mon Sep 17 00:00:00 2001 From: jusohn Date: Sun, 3 Sep 2023 22:54:32 +0900 Subject: [PATCH 190/208] =?UTF-8?q?[FE]=20FIX:=20=EA=B3=B5=EC=9C=A0?= =?UTF-8?q?=EC=82=AC=EB=AC=BC=ED=95=A8=20=EB=8C=80=EA=B8=B0=EC=97=B4?= =?UTF-8?q?=EC=97=90=20=ED=98=BC=EC=9E=90=20=EC=9E=88=EC=9D=84=20=EB=95=8C?= =?UTF-8?q?=EC=97=90=20=EC=97=B0=EC=9E=A5=EA=B6=8C=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EB=B6=88=EA=B0=80=20hover=20=EA=B0=80=20=EB=9C=A8=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CabinetInfoArea/CabinetInfoArea.tsx | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index 30cb26558..874cfc45b 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -172,8 +172,8 @@ const CabinetInfoArea: React.FC<{ {selectedCabinetInfo!.cabinetId === 0 ? "-" : expireDate} - {isExtensible && - isMine && + {isMine && + isExtensible && selectedCabinetInfo.status !== "IN_SESSION" && ( { @@ -189,18 +189,22 @@ const CabinetInfoArea: React.FC<{ } /> )} - - - 공유사물함을 단독으로 이용 시,
- 연장권을 사용할 수 없습니다. -
+ {isMine && + selectedCabinetInfo.lentsLength <= 1 && + selectedCabinetInfo.lentType === "SHARE" && + selectedCabinetInfo.status !== "IN_SESSION" && ( + + + 공유사물함을 단독으로 이용 시,
+ 연장권을 사용할 수 없습니다. +
+ )}
{userModal.unavailableModal && ( (props.canUseExtendTicket ? "1" : "0")}; + opacity: ${(props) => (props.canUseExtendTicket ? "0" : "1")}; `; const AlertImgStyled = styled.img` From 159a210513be9cb9b9a1467b236b38ad2e11727d Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Sun, 3 Sep 2023 23:00:36 +0900 Subject: [PATCH 191/208] =?UTF-8?q?[FE]=20FEAT=20:=20homepage=20ManualCont?= =?UTF-8?q?ent=20Modal=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/data/ManualContent.ts | 113 ++++++ .../src/components/Home/ManualContentBox.tsx | 102 +++-- .../src/components/Home/ServiceManual.tsx | 79 ++-- .../Modals/ManualModal/ManualModal.tsx | 352 ++++++++++++------ .../components/TopNav/SearchBar/SearchBar.tsx | 6 +- .../src/types/enum/content.status.enum.ts | 10 + 6 files changed, 470 insertions(+), 192 deletions(-) create mode 100644 frontend/src/assets/data/ManualContent.ts create mode 100644 frontend/src/types/enum/content.status.enum.ts diff --git a/frontend/src/assets/data/ManualContent.ts b/frontend/src/assets/data/ManualContent.ts new file mode 100644 index 000000000..5393cf524 --- /dev/null +++ b/frontend/src/assets/data/ManualContent.ts @@ -0,0 +1,113 @@ +import ContentStatus from "@/types/enum/content.status.enum"; + +interface ContentStatusData { + contentTitle: string; + imagePath: string; + background: string; + rentalPeriod?: string; + capacity?: string; + contentText: string; + pointColor: string; +} + +export const manualContentData: Record = { + [ContentStatus.PRIVATE]: { + contentTitle: "개인 사물함", + imagePath: "/src/assets/images/privateIcon.svg", + background: "linear-gradient(to bottom, #A17BF3, #8337E5)", + rentalPeriod: `${import.meta.env.VITE_PRIVATE_LENT_PERIOD}일`, + capacity: "1인", + contentText: `◦ 이용 방법
+      1인이 1개의 사물함을 사용합니다.
+      최대 ${ + import.meta.env.VITE_PRIVATE_LENT_PERIOD + }일간 대여할 수 있습니다.

+ ◦ 페널티
+      연체 시 연체되는 일의 제곱 수만큼 페널티가 부과됩니다. + `, + pointColor: "#8ffac7", + }, + [ContentStatus.SHARE]: { + contentTitle: "공유 사물함", + imagePath: "/src/assets/images/shareIcon.svg", + background: "linear-gradient(to bottom, #7EBFFB, #406EE4)", + rentalPeriod: "20일 * N명", + capacity: "2~4인", + contentText: `◦ 이용 방법
+      1개의 사물함을 최대 ${ + import.meta.env.VITE_SHARE_MAX_USER + }인이 사용합니다. 대여한 인원수 * ${ + import.meta.env.VITE_SHARE_LENT_PERIOD + }일간 대여할 수 있습니다.
     사물함 제목과 메모는 대여자들끼리 공유됩니다.
+      대여 만료 기간 이내 반납 시, 잔여 기간의 인원수 / 1만큼 대여 기간이 감소됩니다. +

+ ◦ 페널티
+      연체 시 연체되는 일의 제곱 수만큼 페널티가 부과됩니다. + `, + pointColor: "#f8f684", + }, + [ContentStatus.CLUB]: { + contentTitle: "동아리 사물함", + imagePath: "/src/assets/images/clubIcon.svg", + background: "linear-gradient(to bottom, #F473B1, #D72766)", + rentalPeriod: "상세내용 참조", + capacity: "동아리", + contentText: `모집 기간에만 대여할 수 있습니다. +
+ 새로운 기수가 들어올 때 갱신됩니다. +
+ 사물함 대여는 + + 슬랙 캐비닛 채널 + + 로 문의주세요. +
+ 상세 페이지가 제공되지 않습니다. +
+ 비밀번호는 동아리 내에서 공유하여 이용하세요.`, + pointColor: "#47ffa7", + }, + [ContentStatus.PENDING]: { + contentTitle: "오픈예정", + imagePath: "/src/assets/images/happyCcabi.png", + background: "white", + contentText: `사물함 반납 시, 해당 사물함은 즉시 오픈예정 상태가 됩니다.
+ 오픈예정 상태의 사물함은 대여가 불가능합니다.
+ 오픈예정 상태의 사물함은 반납일 기준 다음 날 오후 1시(13시) 사용가능 상태가 됩니다.
+ 당일 오픈되는 사물함은 + 슬랙 캐비닛 채널에서 확인하세요.`, + pointColor: "#6f07f6", + }, + [ContentStatus.IN_SESSION]: { + contentTitle: "대기중", + imagePath: "/src/assets/images/clock.svg", + background: "#9F72FE", + contentText: `공유 사물함 대여시 10분간의 대기 시간이 발생합니다.
+ 대기 시간 동안 공유 인원(2인~4인)이 형성되지 않으면 공유 사물함 대여는 취소됩니다.
+ 대기 시간 내 4명의 공유 인원이 형성되면 즉시 대여가 완료됩니다.
+ 대여 과정에서 생성된 초대 코드를 사용하여 공유 사물함에 입장할 수 있습니다.
+ 초대 코드를 3번 이상 잘못 입력하면 입장이 제한됩니다. + `, + pointColor: "#47ffa7", + }, + [ContentStatus.EXTENSION]: { + contentTitle: "연장권 이용방법 안내서", + imagePath: "/src/assets/images/extensionTicket.svg", + background: "#F5F5F7", + contentText: `◦ 연장권 취득 조건
+     월 출석 시간이 120시간 이상일 시 연장권이 부여됩니다.
+     연장권은 매달 2일 지급됩니다.

+ ◦ 연장권 사용
+      연장권 사용 시, 대여 만료 기간이 1달(31) 연장됩니다.
+      연장권은 해당 월의 마지막 날까지 사용 가능합니다.`, + pointColor: "#9747FF", + }, +}; diff --git a/frontend/src/components/Home/ManualContentBox.tsx b/frontend/src/components/Home/ManualContentBox.tsx index 993537c08..cefdb3acf 100644 --- a/frontend/src/components/Home/ManualContentBox.tsx +++ b/frontend/src/components/Home/ManualContentBox.tsx @@ -1,62 +1,35 @@ -import { useState } from "react"; -import styled, { css } from "styled-components"; +import styled, { css, keyframes } from "styled-components"; +import { manualContentData } from "@/assets/data/ManualContent"; +import ContentStatus from "@/types/enum/content.status.enum"; interface MaunalContentBoxProps { - contentStatus: string; + contentStatus: ContentStatus; } const MaunalContentBox = ({ contentStatus }: MaunalContentBoxProps) => { - let contentText = ""; - let imagePath = ""; - let background = ""; - - const [isModalOpen, setIsModalOpen] = useState(false); - - if (contentStatus === "private") { - contentText = "개인 사물함"; - imagePath = "/src/assets/images/privateIcon.svg"; - background = "linear-gradient(to bottom, #A17BF3, #8337E5)"; - } else if (contentStatus === "share") { - contentText = "공유 사물함"; - imagePath = "/src/assets/images/shareIcon.svg"; - background = "linear-gradient(to bottom, #7EBFFB, #406EE4)"; - } else if (contentStatus === "club") { - contentText = "동아리 사물함"; - imagePath = "/src/assets/images/clubIcon.svg"; - background = "linear-gradient(to bottom, #F473B1, #D72766)"; - } else if (contentStatus === "pending") { - contentText = "오픈예정"; - imagePath = ""; - } else if (contentStatus === "in_session") { - background = "#9F72FE"; - contentText = "대기중"; - imagePath = ""; - } else if (contentStatus === "extension") { - contentText = "연장권 이용방법 안내서"; - background = "#F5F5F7"; - imagePath = "/src/assets/images/extensionTicket.svg"; - } + const contentData = manualContentData[contentStatus]; return ( - {contentStatus === "extension" && ( + {contentStatus === ContentStatus.EXTENSION && ( )} - {contentStatus !== "pending" && contentStatus !== "in_session" && ( - - )} + {contentStatus !== ContentStatus.PENDING && + contentStatus !== ContentStatus.IN_SESSION && ( + + )} - {contentStatus === "in_session" && ( + {contentStatus === ContentStatus.IN_SESSION && ( )} -

{contentText}

+

{contentData.contentTitle}

{ const MaunalContentBoxStyled = styled.div<{ background: string; - contentStatus: string; + contentStatus: ContentStatus; }>` position: relative; - width: 320px; - height: 320px; + width: 300px; + height: 300px; border-radius: 40px; background: ${(props) => props.background}; display: flex; @@ -84,6 +57,7 @@ const MaunalContentBoxStyled = styled.div<{ padding: 25px; margin-right: 40px; font-weight: bold; + cursor: pointer; .clockImg { width: 35px; @@ -97,7 +71,7 @@ const MaunalContentBoxStyled = styled.div<{ width: 80px; height: 80px; filter: brightness( - ${(props) => (props.contentStatus === "extension" ? 0 : 100)} + ${(props) => (props.contentStatus === ContentStatus.EXTENSION ? 0 : 100)} ); } @@ -111,23 +85,30 @@ const MaunalContentBoxStyled = styled.div<{ } ${({ contentStatus }) => - contentStatus === "pending" && + contentStatus === ContentStatus.PENDING && css` border: 5px solid var(--main-color); color: var(--main-color); `} ${({ contentStatus }) => - contentStatus === "extension" && + contentStatus === ContentStatus.IN_SESSION && css` - width: 1040px; + animation: ${Animation} 3s infinite; + `} + + ${({ contentStatus }) => + contentStatus === ContentStatus.EXTENSION && + css` + width: 960px; color: black; `} p { margin-top: 90px; ${({ contentStatus }) => - (contentStatus === "pending" || contentStatus === "in_session") && + (contentStatus === ContentStatus.PENDING || + contentStatus === ContentStatus.IN_SESSION) && css` margin-top: 170px; `} @@ -141,9 +122,9 @@ const MaunalContentBoxStyled = styled.div<{ bottom: 35px; filter: brightness( ${(props) => - props.contentStatus === "pending" + props.contentStatus === ContentStatus.PENDING ? "none" - : props.contentStatus === "extension" + : props.contentStatus === ContentStatus.EXTENSION ? "0" : "100"} ); @@ -151,21 +132,34 @@ const MaunalContentBoxStyled = styled.div<{ } :hover { + transition: all 0.3s ease-in-out; box-shadow: 10px 10px 25px 0 rgba(0, 0, 0, 0.2); p { - margin-top: 80px; + transition: all 0.3s ease-in-out; + margin-top: 85px; ${({ contentStatus }) => - (contentStatus === "pending" || contentStatus === "in_session") && + (contentStatus === ContentStatus.PENDING || + contentStatus === ContentStatus.IN_SESSION) && css` - margin-top: 160px; + margin-top: 165px; `} } .clockImg { - margin-top: 160px; + transition: all 0.3s ease-in-out; + margin-top: 165px; } } `; +const Animation = keyframes` + 0%, 100% { + background-color: var(--main-color); + } + 50% { + background-color: #eeeeee; + } +`; + const ContentTextStyeld = styled.div` display: flex; align-items: center; diff --git a/frontend/src/components/Home/ServiceManual.tsx b/frontend/src/components/Home/ServiceManual.tsx index 70e87de9c..b1f13fd34 100644 --- a/frontend/src/components/Home/ServiceManual.tsx +++ b/frontend/src/components/Home/ServiceManual.tsx @@ -1,6 +1,8 @@ import { useState } from "react"; import styled from "styled-components"; import MaunalContentBox from "@/components/Home/ManualContentBox"; +import ManualModal from "@/components/Modals/ManualModal/ManualModal"; +import ContentStatus from "@/types/enum/content.status.enum"; const ServiceManual = ({ lentStartHandler, @@ -8,7 +10,12 @@ const ServiceManual = ({ lentStartHandler: React.MouseEventHandler; }) => { const [isModalOpen, setIsModalOpen] = useState(false); - const openModal = () => { + const [selectedContent, setSelectedContent] = useState( + ContentStatus.PRIVATE + ); + + const openModal = (contentStatus: ContentStatus) => { + setSelectedContent(contentStatus); setIsModalOpen(true); }; @@ -30,28 +37,43 @@ const ServiceManual = ({ 개인, 공유, 동아리 사물함.

-
- +
openModal(ContentStatus.PRIVATE)} + > +
-
- +
openModal(ContentStatus.SHARE)} + > +
-
- +
openModal(ContentStatus.CLUB)} + > +

공정한 대여를 위한
- 새로운 사물함 상태. + 새로운 사물함 서비스.

-
- +
openModal(ContentStatus.PENDING)} + > +

new

-
- +
openModal(ContentStatus.IN_SESSION)} + > +

new

@@ -61,12 +83,20 @@ const ServiceManual = ({ 사용할 수 있는 방법.

-
- +
openModal(ContentStatus.EXTENSION)} + > +
+ ); }; @@ -76,7 +106,7 @@ const WrapperStyled = styled.div` flex-direction: column; justify-content: center; align-items: center; - padding: 70px 0; + padding: 60px 0; `; const TitleContainerStyled = styled.div` @@ -122,11 +152,19 @@ const InfoSectionStyled = styled.section` width: 100%; max-width: 1500px; .article { - //width: 100%; display: flex; flex-direction: column; align-items: flex-start; - margin-bottom: 70px; + margin-bottom: 60px; + margin-top: 10px; + :hover { + transition: all 0.3s ease-in-out; + margin-top: 6px; + .redColor { + transition: all 0.3s ease-in-out; + font-weight: 700; + } + } } .article > h3 { min-width: 200px; @@ -143,16 +181,11 @@ const InfoSectionStyled = styled.section` } .redColor { color: #ef8172; - margin: 20px 0 0 140px; + margin: 20px 0 0 135px; } .article > p > span { font-weight: 700; } `; -const AtagStyled = styled.a` - text-decoration: underline; - font-weight: 700; -`; - export default ServiceManual; diff --git a/frontend/src/components/Modals/ManualModal/ManualModal.tsx b/frontend/src/components/Modals/ManualModal/ManualModal.tsx index 3b1f092f1..b633a1c35 100644 --- a/frontend/src/components/Modals/ManualModal/ManualModal.tsx +++ b/frontend/src/components/Modals/ManualModal/ManualModal.tsx @@ -1,123 +1,251 @@ -import React, { useState } from "react"; -import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; -import { - currentCabinetIdState, - isCurrentSectionRenderState, - myCabinetInfoState, - targetCabinetInfoState, - userState, -} from "@/recoil/atoms"; -import Modal, { IModalContents } from "@/components/Modals/Modal"; -import ModalPortal from "@/components/Modals/ModalPortal"; -import { - FailResponseModal, - SuccessResponseModal, -} from "@/components/Modals/ResponseModal/ResponseModal"; -import { modalPropsMap } from "@/assets/data/maps"; -import checkIcon from "@/assets/images/checkIcon.svg"; -import { MyCabinetInfoResponseDto } from "@/types/dto/cabinet.dto"; -import CabinetStatus from "@/types/enum/cabinet.status.enum"; -import { - axiosCabinetById, - axiosLentId, - axiosLentShareId, - axiosMyLentInfo, -} from "@/api/axios/axios.custom"; -import { getExpireDateString } from "@/utils/dateUtils"; - -const ManualModal: React.FC<{ - lentType: string; - closeModal: React.MouseEventHandler; -}> = (props) => { - const [showResponseModal, setShowResponseModal] = useState(false); - const [hasErrorOnResponse, setHasErrorOnResponse] = useState(false); - const [modalTitle, setModalTitle] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const currentCabinetId = useRecoilValue(currentCabinetIdState); - const [myInfo, setMyInfo] = useRecoilState(userState); - const setMyLentInfo = - useSetRecoilState(myCabinetInfoState); - const [targetCabinetInfo, setTargetCabinetInfo] = useRecoilState( - targetCabinetInfoState - ); - const setIsCurrentSectionRender = useSetRecoilState( - isCurrentSectionRenderState - ); +import React from "react"; +import { useState } from "react"; +import styled, { css, keyframes } from "styled-components"; +import { manualContentData } from "@/assets/data/ManualContent"; +import ContentStatus from "@/types/enum/content.status.enum"; + +interface ModalProps { + isOpen: boolean; + contentStatus: ContentStatus; + onClose: () => void; +} + +const ManualModal: React.FC = ({ + isOpen, + contentStatus, + onClose, +}) => { + if (!isOpen) return null; + const [modalIsOpen, setModalIsOpen] = useState(isOpen); + const contentData = manualContentData[contentStatus]; - const formattedExpireDate = getExpireDateString(props.lentType); - const privateLentDetail = `대여기간은 ${formattedExpireDate} 23:59까지 입니다. - 귀중품 분실 및 메모 내용의 유출에 책임지지 않습니다.`; - const shareLentDetail = `대여 후 ${ - 10 - // import.meta.env.VITE_SHARE_LENT_COUNTDOWN // TODO: .env 에 등록하기 - }분 이내에 - 공유 인원 (2인~4인) 이 충족되지 않으면, - 공유 사물함의 대여가 취소됩니다. - “메모 내용”은 공유 인원끼리 공유됩니다. - 귀중품 분실 및 메모 내용의 유출에 책임지지 않습니다.`; - const tryLentRequest = async (e: React.MouseEvent) => { - setIsLoading(true); - try { - if (props.lentType == "SHARE") - await axiosLentShareId(currentCabinetId, "0"); - else await axiosLentId(currentCabinetId); - //userCabinetId 세팅 - setMyInfo({ ...myInfo, cabinetId: currentCabinetId }); - setIsCurrentSectionRender(true); - if (props.lentType == "SHARE") - setModalTitle("공유 사물함 대기열에 입장하였습니다"); - else setModalTitle("대여가 완료되었습니다"); - // 캐비닛 상세정보 바꾸는 곳 - try { - const { data } = await axiosCabinetById(currentCabinetId); - setTargetCabinetInfo(data); - } catch (error) { - throw error; - } - // 내 대여정보 바꾸는 곳 - try { - const { data: myLentInfo } = await axiosMyLentInfo(); - setMyLentInfo(myLentInfo); - } catch (error) { - throw error; - } - } catch (error: any) { - setModalTitle(error.response.data.message); - setHasErrorOnResponse(true); - } finally { - setIsLoading(false); - setShowResponseModal(true); + const isCabinetType = + contentStatus === ContentStatus.PRIVATE || + contentStatus === ContentStatus.SHARE || + contentStatus === ContentStatus.CLUB; + + const handleModalClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + setModalIsOpen(false); + setTimeout(() => { + onClose(); + }, 400); } }; - const lentModalContents: IModalContents = { - type: "hasProceedBtn", - icon: checkIcon, - title: modalPropsMap[CabinetStatus.AVAILABLE].title, - detail: props.lentType === "PRIVATE" ? privateLentDetail : shareLentDetail, - proceedBtnText: modalPropsMap[CabinetStatus.AVAILABLE].confirmMessage, - onClickProceed: tryLentRequest, - closeModal: props.closeModal, - isLoading: isLoading, + const closeModal = () => { + setModalIsOpen(false); + setTimeout(() => { + onClose(); + }, 400); }; return ( - - {!showResponseModal && } - {showResponseModal && - (hasErrorOnResponse ? ( - - ) : ( - - ))} - + + + + + + + + + {isCabinetType && ( + + + 대여기간 +
+ {contentData.rentalPeriod} +
+ + 사용인원 +
+ {contentData.capacity} +
+
+ )} +
+ {contentData.contentTitle} + +
+
+
+
+
); }; +const ModalOverlay = styled.div` + position: fixed; + top: 0; + left: 75px; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + z-index: 9999; +`; + +const OpenModalAni = keyframes` + from { + transform: translateY(100%) scale(0.8); + opacity: 0; + } + to { + transform: translateY(0) scale(1); + opacity: 1; + } +`; + +const CloseModalAni = keyframes` + from { + transform: translateY(0); + } + to { + transform: translateY(100%); + } +`; + +const ModalWrapper = styled.div<{ + background: string; + contentStatus: ContentStatus; + isOpen: boolean; +}>` + animation: ${(props) => (props.isOpen ? OpenModalAni : CloseModalAni)} 0.4s + ease-in-out; + transform-origin: center; + position: fixed; + bottom: 0; + max-width: 1500px; + width: 72%; + height: 75%; + background: ${(props) => props.background}; + padding: 40px 50px; + border-radius: 40px 40px 0 0; + border: ${(props) => + props.contentStatus === ContentStatus.PENDING + ? "6px solid #9747FF" + : "none"}; + border-bottom: none; +`; + +const ModalContent = styled.div<{ + contentStatus: ContentStatus; +}>` + height: 100%; + display: flex; + flex-direction: column; + color: ${(props) => + props.contentStatus === ContentStatus.PENDING + ? "var(--main-color)" + : props.contentStatus === ContentStatus.EXTENSION + ? "black" + : "white"}; + font-size: 40px; + font-weight: bold; + align-items: flex-start; + .contentImg { + width: 80px; + height: 80px; + filter: ${(props) => + props.contentStatus === ContentStatus.EXTENSION + ? "brightness(0)" + : "brightness(100)"}; + background-color: ${(props) => + props.contentStatus === ContentStatus.PENDING + ? "var(--main-color)" + : "none"}; + border-radius: ${(props) => + props.contentStatus === ContentStatus.PENDING ? "50px" : "0px"}; + } +`; + +const CloseButton = styled.div<{ + contentStatus: ContentStatus; +}>` + width: 60px; + height: 15px; + cursor: pointer; + margin-bottom: 40px; + align-self: flex-end; + img { + filter: ${(props) => + props.contentStatus === ContentStatus.EXTENSION + ? "brightness(0)" + : props.contentStatus === ContentStatus.PENDING + ? "none" + : "brightness(100)"}; + transform: scaleX(-1); + } +`; + +const BasicInfo = styled.div` + width: 100%; + margin-bottom: 30px; + display: flex; + justify-content: space-between; +`; + +const BoxInfoWrap = styled.div` + display: flex; +`; + +const BoxInfo1 = styled.div` + width: 100px; + height: 80px; + border: 1px solid white; + border-radius: 15px; + font-size: 14px; + font-weight: 400; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + flex-direction: column; + align-self: flex-end; + strong { + margin-top: 10px; + } +`; + +const BoxInfo2 = styled.div` + width: 80px; + height: 80px; + border: 1px solid white; + border-radius: 15px; + font-size: 14px; + font-weight: 400; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + flex-direction: column; + margin-left: 10px; + strong { + margin-top: 10px; + } +`; + +const ManualContentStyeld = styled.div<{ + color: string; +}>` + margin: 40px 0 0 10px; + font-size: 20px; + line-height: 1.9; + font-weight: 350; + strong { + color: ${(props) => props.color}; + } + a { + font-weight: bold; + color: ${(props) => props.color}; + } +`; + export default ManualModal; diff --git a/frontend/src/components/TopNav/SearchBar/SearchBar.tsx b/frontend/src/components/TopNav/SearchBar/SearchBar.tsx index 4ff4aa443..3c0f046b9 100644 --- a/frontend/src/components/TopNav/SearchBar/SearchBar.tsx +++ b/frontend/src/components/TopNav/SearchBar/SearchBar.tsx @@ -206,14 +206,14 @@ const SearchBarStyled = styled.div` const SearchBarInputStyled = styled.input` width: 300px; height: 40px; - border: 1px solid var(--white); + border: 1px solid #7b7b7b; border-radius: 10px; text-align: left; padding: 0 20px; - color: var(--white); + color: #7b7b7b; background-color: rgba(255, 255, 255, 0.2); &::placeholder { - color: var(--white); + color: #7b7b7b; } `; diff --git a/frontend/src/types/enum/content.status.enum.ts b/frontend/src/types/enum/content.status.enum.ts new file mode 100644 index 000000000..cb348bd85 --- /dev/null +++ b/frontend/src/types/enum/content.status.enum.ts @@ -0,0 +1,10 @@ +export enum ContentStatus { + PRIVATE = "PRIVATE", + SHARE = "SHARE", + CLUB = "CLUB", + PENDING = "PENDING", + IN_SESSION = "IN_SESSION", + EXTENSION = "EXTENSION", +} + +export default ContentStatus; From e28a84adb3ea1d068698f817f400669f14028ab8 Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Mon, 4 Sep 2023 00:44:07 +0900 Subject: [PATCH 192/208] =?UTF-8?q?[FE]=20FEAT=20:=20newHomepage=20?= =?UTF-8?q?=EB=B0=98=EC=9D=91=ED=98=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/css/homePage.css | 6 +- frontend/src/assets/data/ManualContent.ts | 6 +- .../src/components/Home/ManualContentBox.tsx | 29 +-- .../src/components/Home/ServiceManual.tsx | 19 +- frontend/src/components/Home/tmp.tsx | 203 ------------------ .../Modals/ManualModal/ManualModal.tsx | 21 +- 6 files changed, 51 insertions(+), 233 deletions(-) delete mode 100644 frontend/src/components/Home/tmp.tsx diff --git a/frontend/src/assets/css/homePage.css b/frontend/src/assets/css/homePage.css index 309dcc43b..e71b6c4bf 100644 --- a/frontend/src/assets/css/homePage.css +++ b/frontend/src/assets/css/homePage.css @@ -1,7 +1,7 @@ -@media screen and (max-width: 1300px) { +@media screen and (max-width: 1100px) { #infoWrap > .titleContainer { width: 90%; - max-width: 600px; + max-width: 800px; } #infoWrap .section { @@ -10,6 +10,8 @@ } #infoWrap .article { width: 100%; + align-items: center; + margin-right: 0px; } } diff --git a/frontend/src/assets/data/ManualContent.ts b/frontend/src/assets/data/ManualContent.ts index 5393cf524..be50b8b08 100644 --- a/frontend/src/assets/data/ManualContent.ts +++ b/frontend/src/assets/data/ManualContent.ts @@ -42,7 +42,7 @@ export const manualContentData: Record = {      대여 만료 기간 이내 반납 시, 잔여 기간의 인원수 / 1만큼 대여 기간이 감소됩니다.

◦ 페널티
-      연체 시 연체되는 일의 제곱 수만큼 페널티가 부과됩니다. +      연체 시 연체되는 일의 제곱 수만큼 페널티가 부과됩니다.

`, pointColor: "#f8f684", }, @@ -94,7 +94,7 @@ export const manualContentData: Record = { 대기 시간 동안 공유 인원(2인~4인)이 형성되지 않으면 공유 사물함 대여는 취소됩니다.
대기 시간 내 4명의 공유 인원이 형성되면 즉시 대여가 완료됩니다.
대여 과정에서 생성된 초대 코드를 사용하여 공유 사물함에 입장할 수 있습니다.
- 초대 코드를 3번 이상 잘못 입력하면 입장이 제한됩니다. + 초대 코드를 3번 이상 잘못 입력하면 입장이 제한됩니다.

`, pointColor: "#47ffa7", }, @@ -106,7 +106,7 @@ export const manualContentData: Record = {     월 출석 시간이 120시간 이상일 시 연장권이 부여됩니다.
    연장권은 매달 2일 지급됩니다.

◦ 연장권 사용
-      연장권 사용 시, 대여 만료 기간이 1달(31) 연장됩니다.
+      연장권 사용 시, 대여 만료 기간이 1달(31일) 연장됩니다.
     연장권은 해당 월의 마지막 날까지 사용 가능합니다.`, pointColor: "#9747FF", }, diff --git a/frontend/src/components/Home/ManualContentBox.tsx b/frontend/src/components/Home/ManualContentBox.tsx index cefdb3acf..aeffba7e8 100644 --- a/frontend/src/components/Home/ManualContentBox.tsx +++ b/frontend/src/components/Home/ManualContentBox.tsx @@ -45,26 +45,24 @@ const MaunalContentBoxStyled = styled.div<{ contentStatus: ContentStatus; }>` position: relative; - width: 300px; - height: 300px; + width: 280px; + height: 280px; border-radius: 40px; background: ${(props) => props.background}; display: flex; flex-direction: column; align-items: flex-start; - font-size: 32px; + font-size: 28px; color: white; padding: 25px; - margin-right: 40px; font-weight: bold; cursor: pointer; - .clockImg { width: 35px; height: 35px; filter: brightness(100); margin-right: 10px; - margin-top: 170px; + margin-top: 160px; } .contentImg { @@ -100,17 +98,24 @@ const MaunalContentBoxStyled = styled.div<{ ${({ contentStatus }) => contentStatus === ContentStatus.EXTENSION && css` - width: 960px; + width: 900px; color: black; + @media screen and (max-width: 1000px) { + width: 280px; + .peopleImg { + display: none; + } + font-size: 21px; + } `} p { - margin-top: 90px; + margin-top: 80px; ${({ contentStatus }) => (contentStatus === ContentStatus.PENDING || contentStatus === ContentStatus.IN_SESSION) && css` - margin-top: 170px; + margin-top: 160px; `} } @@ -136,17 +141,17 @@ const MaunalContentBoxStyled = styled.div<{ box-shadow: 10px 10px 25px 0 rgba(0, 0, 0, 0.2); p { transition: all 0.3s ease-in-out; - margin-top: 85px; + margin-top: 75px; ${({ contentStatus }) => (contentStatus === ContentStatus.PENDING || contentStatus === ContentStatus.IN_SESSION) && css` - margin-top: 165px; + margin-top: 155px; `} } .clockImg { transition: all 0.3s ease-in-out; - margin-top: 165px; + margin-top: 155px; } } `; diff --git a/frontend/src/components/Home/ServiceManual.tsx b/frontend/src/components/Home/ServiceManual.tsx index b1f13fd34..004c17743 100644 --- a/frontend/src/components/Home/ServiceManual.tsx +++ b/frontend/src/components/Home/ServiceManual.tsx @@ -110,13 +110,14 @@ const WrapperStyled = styled.div` `; const TitleContainerStyled = styled.div` - width: 70%; + width: 80%; + max-width: 1000px; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; border-bottom: 2px solid #d9d9d9; - margin-bottom: 100px; + margin-bottom: 70px; color: var(--main-color); font-weight: 700; .logo { @@ -135,8 +136,8 @@ const TitleContainerStyled = styled.div` `; const WrapSectionStyled = styled.div` - width: 70%; - max-width: 1500px; + width: 80%; + max-width: 1000px; .subtitle { font-size: 2.5rem; line-height: 1.4; @@ -147,16 +148,14 @@ const WrapSectionStyled = styled.div` const InfoSectionStyled = styled.section` display: flex; - margin-top: 40px; - margin-bottom: 60px; + margin: 40px 0 60px 0; width: 100%; max-width: 1500px; .article { display: flex; flex-direction: column; - align-items: flex-start; - margin-bottom: 60px; - margin-top: 10px; + align-items: center; + margin: 10px 40px 60px 0; :hover { transition: all 0.3s ease-in-out; margin-top: 6px; @@ -181,7 +180,7 @@ const InfoSectionStyled = styled.section` } .redColor { color: #ef8172; - margin: 20px 0 0 135px; + margin-top: 15px; } .article > p > span { font-weight: 700; diff --git a/frontend/src/components/Home/tmp.tsx b/frontend/src/components/Home/tmp.tsx deleted file mode 100644 index 789e51797..000000000 --- a/frontend/src/components/Home/tmp.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import styled from "styled-components"; -import MaunalContentBox from "@/components/Home/ManualContentBox"; - -const ServiceManual = ({ - lentStartHandler, -}: { - lentStartHandler: React.MouseEventHandler; -}) => { - return ( - - -
- -
-

- 42Cabi 이용 안내서 -

-
- -

- 가능성의 확장 -
- 개인, 공유, 동아리 사물함. -

- -
- -
- -
-

- 1인이 1개의 사물함을 사용합니다. -
- 최대 - {import.meta.env.VITE_PRIVATE_LENT_PERIOD}일간 - {" "} - 대여할 수 있습니다. -
- 연체 시 연체되는{" "} - 일 수만큼 페널티가 부과됩니다. -

-
-
- -
- -
-

공유 사물함

-

- 1개의 사물함을 최대{" "} - {import.meta.env.VITE_SHARE_MAX_USER}인이 사용합니다. -
- {import.meta.env.VITE_SHARE_LENT_PERIOD}일간 대여할 - 수 있습니다. -
- 사물함 제목과 메모는 대여자들끼리 공유됩니다. -
- 대여 후{" "} - - {import.meta.env.VITE_SHARE_EARLY_RETURN_PERIOD}시간 - {" "} - 내 반납 시, -
- {import.meta.env.VITE_SHARE_EARLY_RETURN_PENALTY}시간 동안 공유 - 사물함 대여가 - 불가능합니다. -
- 연체 시 연체되는{" "} - 일 수만큼 페널티가 부과됩니다. -

-
-
- -
- -
-

동아리 사물함

-

- 모집 기간에만 대여할 수 있습니다. -
- 새로운 기수가 들어올 때 갱신됩니다. -
- 사물함 대여는{" "} - - 슬랙 캐비닛 채널 - - 로 문의주세요. -
- 상세 페이지가 제공되지 않습니다. -
- 비밀번호는 동아리 내에서 공유하여 이용하세요. -

-
-
-

- 공정한 대여를 위한 -
- 새로운 사물함 상태. -

-
- -
- ); -}; - -const WrapperStyled = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 70px 0; -`; - -const TitleContainerStyled = styled.div` - width: 600px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - border-bottom: 2px solid #d9d9d9; - .logo { - width: 35px; - height: 35px; - margin-bottom: 20px; - } - .title { - font-size: 2.5rem; - letter-spacing: -0.02rem; - margin-bottom: 20px; - } - .title > span { - font-weight: 700; - } -`; - -const WrapSectionStyled = styled.div` - width: 70%; - max-width: 1500px; - .subtitle { - font-size: 2.5rem; - line-height: 1.4; - text-align: left; - font-weight: bold; - } -`; - -const InfoSectionStyled = styled.section` - display: flex; - justify-content: space-between; - margin-top: 40px; - width: 100%; - max-width: 1500px; - .article { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - margin-bottom: 70px; - } - .article > div { - /* width: 58px; - height: 58px; */ - //display: flex; - //justify-content: center; - //align-items: center; - //background-color: rgba(113, 46, 255, 0.1); - //border-radius: 50%; - } - /* .article > div > img { - width: 24px; - height: 24px; - } */ - .article > h3 { - min-width: 200px; - text-align: center; - font-size: 1.5rem; - margin: 15px 0; - font-weight: 700; - } - .article > p { - font-size: 1.125rem; - line-height: 1.6; - letter-spacing: -0.02rem; - text-align: center; - } - .redColor { - color: var(--expired); - } - .article > p > span { - font-weight: 700; - } -`; - -const AtagStyled = styled.a` - text-decoration: underline; - font-weight: 700; -`; - -export default ServiceManual; diff --git a/frontend/src/components/Modals/ManualModal/ManualModal.tsx b/frontend/src/components/Modals/ManualModal/ManualModal.tsx index b633a1c35..095bea92f 100644 --- a/frontend/src/components/Modals/ManualModal/ManualModal.tsx +++ b/frontend/src/components/Modals/ManualModal/ManualModal.tsx @@ -83,7 +83,6 @@ const ManualModal: React.FC = ({ const ModalOverlay = styled.div` position: fixed; top: 0; - left: 75px; width: 100%; height: 100%; display: flex; @@ -122,8 +121,8 @@ const ModalWrapper = styled.div<{ transform-origin: center; position: fixed; bottom: 0; - max-width: 1500px; - width: 72%; + max-width: 1000px; + width: 70%; height: 75%; background: ${(props) => props.background}; padding: 40px 50px; @@ -133,6 +132,10 @@ const ModalWrapper = styled.div<{ ? "6px solid #9747FF" : "none"}; border-bottom: none; + overflow-y: auto; + @media screen and (max-width: 650px) { + width: 100%; + } `; const ModalContent = styled.div<{ @@ -164,6 +167,14 @@ const ModalContent = styled.div<{ border-radius: ${(props) => props.contentStatus === ContentStatus.PENDING ? "50px" : "0px"}; } + @media screen and (max-width: 650px) { + font-size: 25px; + .contentImg { + width: 60px; + height: 60px; + margin-top: 10px; + } + } `; const CloseButton = styled.div<{ @@ -246,6 +257,10 @@ const ManualContentStyeld = styled.div<{ font-weight: bold; color: ${(props) => props.color}; } + @media screen and (max-width: 650px) { + line-height: 1.4; + font-size: 16px; + } `; export default ManualModal; From 67104e668f95d90e9c0be59d7c272c6fd6e9d1f5 Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Mon, 4 Sep 2023 00:52:59 +0900 Subject: [PATCH 193/208] =?UTF-8?q?[FE]=20DESIGN=20:=20=EB=AA=A8=EB=8B=AC?= =?UTF-8?q?=20overflow=20auto=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Modals/ManualModal/ManualModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Modals/ManualModal/ManualModal.tsx b/frontend/src/components/Modals/ManualModal/ManualModal.tsx index 095bea92f..05faa5717 100644 --- a/frontend/src/components/Modals/ManualModal/ManualModal.tsx +++ b/frontend/src/components/Modals/ManualModal/ManualModal.tsx @@ -132,9 +132,9 @@ const ModalWrapper = styled.div<{ ? "6px solid #9747FF" : "none"}; border-bottom: none; - overflow-y: auto; @media screen and (max-width: 650px) { width: 100%; + overflow-y: auto; } `; From 3d4c3a33e899a0c896e91601e9d204c4d6470a52 Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Mon, 4 Sep 2023 02:14:40 +0900 Subject: [PATCH 194/208] =?UTF-8?q?[FE]=20FEAT=20:=20=EC=9D=B4=EC=A0=84=20?= =?UTF-8?q?=EB=8C=80=EC=97=AC=EC=9E=90=20=EB=B3=B4=EC=97=AC=EC=A3=BC?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CabinetInfoArea.container.tsx | 1 + .../CabinetInfoArea/CabinetInfoArea.tsx | 58 ++++++++++++++++++- frontend/src/types/dto/cabinet.dto.ts | 2 + 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx index baa84e93c..7440b9896 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx @@ -327,6 +327,7 @@ const CabinetInfoAreaContainer = (): JSX.Element => { userModal={userModal} openModal={openModal} closeModal={closeModal} + previousUserName={myCabinetInfo.previousUserName} /> ); }; diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index fb15dd021..42e9b332c 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { useState } from "react"; import styled, { css, keyframes } from "styled-components"; import { ICurrentModalStateInfo, @@ -35,6 +36,7 @@ const CabinetInfoArea: React.FC<{ userModal: ICurrentModalStateInfo; openModal: (modalName: TModalState) => void; closeModal: (modalName: TModalState) => void; + previousUserName: string | null; }> = ({ selectedCabinetInfo, closeCabinet, @@ -45,7 +47,13 @@ const CabinetInfoArea: React.FC<{ userModal, openModal, closeModal, + previousUserName, }) => { + const [showPreviousUser, setShowPreviousUser] = useState(false); + + const handleLinkTextClick = () => { + setShowPreviousUser(!showPreviousUser); + }; return selectedCabinetInfo === null ? ( @@ -86,7 +94,6 @@ const CabinetInfoArea: React.FC<{ }} text="대기열 취소" theme="fill" - //disabled={timeOver} /> + + {showPreviousUser ? ( + previousUserName + ) : ( + <> + + + 이전
+ 대여자 +
+ + )} +
) ) : ( @@ -251,6 +274,39 @@ const CabinetDetailAreaStyled = styled.div` align-items: center; `; +const LinkTextStyled = styled.div` + position: absolute; + bottom: 3%; + right: 7%; + font-size: 0.875rem; + font-weight: 400; + line-height: 0.875rem; + color: var(--gray-color); + :hover { + cursor: pointer; + } +`; + +const HoverTextStyled = styled.div` + width: 50px; + display: none; + position: absolute; + bottom: 35px; + right: -10px; + color: var(--gray-color); + text-align: center; + line-height: 1.2; +`; + +const ImageStyled = styled.img` + width: 30px; + height: 30px; + + &:hover + ${HoverTextStyled} { + display: block; + } +`; + const CabiLogoStyled = styled.img` width: 35px; height: 35px; diff --git a/frontend/src/types/dto/cabinet.dto.ts b/frontend/src/types/dto/cabinet.dto.ts index 424774143..14a846c93 100644 --- a/frontend/src/types/dto/cabinet.dto.ts +++ b/frontend/src/types/dto/cabinet.dto.ts @@ -7,6 +7,7 @@ import CabinetType from "@/types/enum/cabinet.type.enum"; export interface MyCabinetInfoResponseDto extends CabinetInfo { memo: string; // 사물함 비밀번호와 관련된 메모 shareCode: number; + previousUserName: string; } export interface CabinetBuildingFloorDto { @@ -35,6 +36,7 @@ export interface CabinetInfo { lents: LentDto[]; statusNote: string | null; sessionExpiredAt?: Date; + previousUserName: string | null; } export interface CabinetPreview { From 90bc5fd09e3328936a08fad83e9db29365b14853 Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Mon, 4 Sep 2023 02:20:29 +0900 Subject: [PATCH 195/208] =?UTF-8?q?[FE]=20BUG=20:=20previousUserName=20opt?= =?UTF-8?q?ianal=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/types/dto/cabinet.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/types/dto/cabinet.dto.ts b/frontend/src/types/dto/cabinet.dto.ts index 14a846c93..b68c755df 100644 --- a/frontend/src/types/dto/cabinet.dto.ts +++ b/frontend/src/types/dto/cabinet.dto.ts @@ -36,7 +36,7 @@ export interface CabinetInfo { lents: LentDto[]; statusNote: string | null; sessionExpiredAt?: Date; - previousUserName: string | null; + previousUserName?: string | null; } export interface CabinetPreview { From e3518827925af5ea125fd6d54dbb4138a5d40821 Mon Sep 17 00:00:00 2001 From: moonseonghui Date: Mon, 4 Sep 2023 02:24:22 +0900 Subject: [PATCH 196/208] =?UTF-8?q?[FE]=20DELETE=20CabinetInfo=EC=97=90?= =?UTF-8?q?=EC=84=9C=20previousUserName=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/types/dto/cabinet.dto.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/types/dto/cabinet.dto.ts b/frontend/src/types/dto/cabinet.dto.ts index b68c755df..e29e67987 100644 --- a/frontend/src/types/dto/cabinet.dto.ts +++ b/frontend/src/types/dto/cabinet.dto.ts @@ -36,7 +36,6 @@ export interface CabinetInfo { lents: LentDto[]; statusNote: string | null; sessionExpiredAt?: Date; - previousUserName?: string | null; } export interface CabinetPreview { From 2ca5657df276d4060d9cac99048a11b778de77f1 Mon Sep 17 00:00:00 2001 From: yubinquitous Date: Mon, 4 Sep 2023 17:18:01 +0900 Subject: [PATCH 197/208] =?UTF-8?q?[CHORE]=20redis=20shadow=20key=20expire?= =?UTF-8?q?=20time=EC=9D=84=2030=EC=B4=88=EC=97=90=EC=84=9C=2010=EB=B6=84?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cabinet/service/CabinetServiceImpl.java | 2 +- .../cabinet/lent/repository/LentRedis.java | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/backend/src/main/java/org/ftclub/cabinet/cabinet/service/CabinetServiceImpl.java b/backend/src/main/java/org/ftclub/cabinet/cabinet/service/CabinetServiceImpl.java index 7d312a1e9..dafc83f52 100644 --- a/backend/src/main/java/org/ftclub/cabinet/cabinet/service/CabinetServiceImpl.java +++ b/backend/src/main/java/org/ftclub/cabinet/cabinet/service/CabinetServiceImpl.java @@ -124,7 +124,7 @@ public void updateLentType(Long cabinetId, LentType lentType) { cabinet.specifyLentType(lentType); if (lentType == LentType.SHARE) { cabinet.specifyMaxUser(Math.toIntExact( - cabinetProperties.getShareMaxUserCount())); // todo : policy에서 외부에서 설정된 properties 변수로 설정하게끔 수정 + cabinetProperties.getShareMaxUserCount())); } else { // club 도 1명으로 변경 cabinet.specifyMaxUser(1); } diff --git a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java index eae344e1d..9a7264244 100644 --- a/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java +++ b/backend/src/main/java/org/ftclub/cabinet/lent/repository/LentRedis.java @@ -1,12 +1,5 @@ package org.ftclub.cabinet.lent.repository; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Map; -import java.util.Objects; -import java.util.Random; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import lombok.extern.log4j.Log4j2; import org.ftclub.cabinet.exception.ExceptionStatus; import org.ftclub.cabinet.exception.ServiceException; @@ -16,6 +9,14 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + @Component @Log4j2 public class LentRedis { @@ -33,9 +34,9 @@ public class LentRedis { @Autowired public LentRedis(RedisTemplate valueHashRedisTemplate, - RedisTemplate valueRedisTemplate, - RedisTemplate shadowKeyRedisTemplate, - RedisTemplate previousUserRedisTemplate) { + RedisTemplate valueRedisTemplate, + RedisTemplate shadowKeyRedisTemplate, + RedisTemplate previousUserRedisTemplate) { this.valueOperations = valueRedisTemplate.opsForValue(); this.valueHashOperations = valueHashRedisTemplate.opsForHash(); this.shadowKeyRedisTemplate = shadowKeyRedisTemplate; @@ -49,7 +50,7 @@ public LentRedis(RedisTemplate valueHashRedisTemplate, * @param hasShadowKey : 최초 대여인지 아닌지 여부 */ public void saveUserInRedis(String cabinetId, String userId, String shareCode, - boolean hasShadowKey) { + boolean hasShadowKey) { log.debug("called saveUserInRedis: {}, {}, {}, {}", cabinetId, userId, shareCode, hasShadowKey); if (!hasShadowKey || isValidShareCode(Long.valueOf(cabinetId), @@ -111,7 +112,7 @@ public void setShadowKey(Long cabinetId) { shadowKeyRedisTemplate.opsForValue().set(shadowKey, shareCode.toString()); // 해당 키가 처음 생성된 것이라면 timeToLive 설정 log.debug("called setShadowKey: {}, shareCode: {}", shadowKey, shareCode); - shadowKeyRedisTemplate.expire(shadowKey, 30, TimeUnit.SECONDS); // TODO: 10분으로 수정 + shadowKeyRedisTemplate.expire(shadowKey, 10, TimeUnit.MINUTES); } public Boolean isShadowKey(Long cabinetId) { From c1e891f7bdf26fcfb67c1e26cdb766ded35b3c36 Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 17:33:32 +0900 Subject: [PATCH 198/208] =?UTF-8?q?[FE]=20FIX:=20=EB=8C=80=EA=B8=B0?= =?UTF-8?q?=EC=97=B4=20=EC=9E=85=EC=9E=A5=20=EC=8B=9C=20=EB=82=B4=20?= =?UTF-8?q?=EC=BC=80=EB=B9=84=EB=84=B7=20=EC=A0=95=EB=B3=B4=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8,=20=EC=82=AC=EB=AC=BC=ED=95=A8?= =?UTF-8?q?=EC=97=90=20=EB=B3=80=ED=99=94=EA=B0=80=20=EC=9E=88=EC=9C=BC?= =?UTF-8?q?=EB=A9=B4=20CCabinetInfoArea=20=EC=97=90=20=EC=97=B4=EB=A0=A4?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EC=82=AC=EB=AC=BC=ED=95=A8=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=9A=94=EC=B2=AD=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TopNavButtonGroup/TopNavButtonGroup.tsx | 58 ++++++++++++++----- frontend/src/pages/MainPage.tsx | 51 ++++++++-------- 2 files changed, 70 insertions(+), 39 deletions(-) diff --git a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx index c86385b73..34aa8aea7 100644 --- a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx +++ b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx @@ -1,20 +1,25 @@ import { useLocation, useNavigate } from "react-router-dom"; -import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; +import { useRecoilState, useSetRecoilState } from "recoil"; import styled from "styled-components"; import { currentCabinetIdState, + myCabinetInfoState, targetCabinetInfoState, + targetUserInfoState, userState, } from "@/recoil/atoms"; import TopNavButton from "@/components/TopNav/TopNavButtonGroup/TopNavButton/TopNavButton"; -import { CabinetInfo } from "@/types/dto/cabinet.dto"; +import { CabinetInfo, MyCabinetInfoResponseDto } from "@/types/dto/cabinet.dto"; import { LentDto } from "@/types/dto/lent.dto"; +import { UserInfo } from "@/types/dto/user.dto"; import { UserDto } from "@/types/dto/user.dto"; import CabinetStatus from "@/types/enum/cabinet.status.enum"; import CabinetType from "@/types/enum/cabinet.type.enum"; import { axiosCabinetById, axiosDeleteCurrentBanLog, + axiosMyInfo, + axiosMyLentInfo, } from "@/api/axios/axios.custom"; import useMenu from "@/hooks/useMenu"; @@ -45,14 +50,19 @@ const TopNavButtonGroup = ({ isAdmin }: { isAdmin?: boolean }) => { const [currentCabinetId, setCurrentCabinetId] = useRecoilState( currentCabinetIdState ); - const setTargetCabinetInfo = useSetRecoilState( + + const setMyLentInfo = + useSetRecoilState(myCabinetInfoState); + const [targetCabinetInfo, setTargetCabinetInfo] = useRecoilState( targetCabinetInfoState ); - const myInfo = useRecoilValue(userState); + const [myInfo, setMyInfo] = useRecoilState(userState); + const [myInfoData, setMyInfoData] = + useRecoilState(targetUserInfoState); const { pathname } = useLocation(); const navigator = useNavigate(); - async function setTargetCabinetInfoToMyCabinet() { + const setTargetCabinetInfoToMyCabinet = async () => { if (myInfo.cabinetId === null) { const defaultCabinetInfo = getDefaultCabinetInfo(myInfo); setTargetCabinetInfo(defaultCabinetInfo); @@ -60,23 +70,41 @@ const TopNavButtonGroup = ({ isAdmin }: { isAdmin?: boolean }) => { return; } setCurrentCabinetId(myInfo.cabinetId); + setMyInfoData(myInfoData); try { const { data } = await axiosCabinetById(myInfo.cabinetId); setTargetCabinetInfo(data); } catch (error) { console.log(error); } - } + }; - const clickMyCabinet = () => { - if (myInfo.cabinetId === null) { - setTargetCabinetInfoToMyCabinet(); - toggleCabinet(); - } else if (currentCabinetId !== myInfo.cabinetId) { - setTargetCabinetInfoToMyCabinet(); - openCabinet(); - } else { - toggleCabinet(); + const clickMyCabinet = async () => { + try { + const { data: myInfo } = await axiosMyInfo(); + setMyInfo(myInfo); + } catch (error: any) { + throw error; + } finally { + if (myInfo.cabinetId === null) { + setTargetCabinetInfoToMyCabinet(); + toggleCabinet(); + } else if (currentCabinetId !== myInfo.cabinetId) { + setTargetCabinetInfoToMyCabinet(); + openCabinet(); + } else { + toggleCabinet(); + } + try { + const { data: myLentInfo } = await axiosMyLentInfo(); + if (myLentInfo) { + setMyLentInfo(myLentInfo); + setMyInfo({ ...myInfo, cabinetId: myLentInfo.cabinetId }); + setTargetCabinetInfo(myLentInfo); + } + } catch (error) { + throw error; + } } }; diff --git a/frontend/src/pages/MainPage.tsx b/frontend/src/pages/MainPage.tsx index 9f94c51fe..1e1fa4290 100644 --- a/frontend/src/pages/MainPage.tsx +++ b/frontend/src/pages/MainPage.tsx @@ -21,12 +21,15 @@ import CabinetListContainer from "@/components/CabinetList/CabinetList.container import LoadingAnimation from "@/components/Common/LoadingAnimation"; import SectionPaginationContainer from "@/components/SectionPagination/SectionPagination.container"; import { + CabinetBuildingFloorDto, CabinetInfoByBuildingFloorDto, + CabinetPreviewInfo, MyCabinetInfoResponseDto, } from "@/types/dto/cabinet.dto"; import { UserDto, UserInfo } from "@/types/dto/user.dto"; import { axiosCabinetByBuildingFloor, + axiosCabinetById, axiosMyInfo, axiosMyLentInfo, } from "@/api/axios/axios.custom"; @@ -70,12 +73,14 @@ const MainPage = () => { CabinetInfoByBuildingFloorDto[] >(currentFloorCabinetState); const setCurrentSection = useSetRecoilState(currentSectionNameState); - const myInfo = useRecoilValue(userState); + const [myInfo, setMyInfo] = useRecoilState(userState); const [myCabinetInfo, setMyLentInfo] = useRecoilState(myCabinetInfoState); + const [targetCabinetInfo, setTargetCabinetInfo] = useRecoilState( + targetCabinetInfoState + ); const [myInfoData, setMyInfoData] = useState(null); - const setUser = useSetRecoilState(userState); const refreshCabinetList = async () => { setIsLoading(true); if ( @@ -85,42 +90,40 @@ const MainPage = () => { try { const { data: myLentInfo } = await axiosMyLentInfo(); setMyLentInfo(myLentInfo); + setMyInfo(myLentInfo.cabinetId); } catch (error) { throw error; } } try { await axiosCabinetByBuildingFloor(currentBuilding, currentFloor) - .then((response) => { + .then(async (response) => { setCurrentFloorData(response.data); - const sections = response.data.map( - (data: CabinetInfoByBuildingFloorDto) => data.section - ); - let currentSectionFromPersist = undefined; - const recoilPersist = localStorage.getItem("recoil-persist"); - if (recoilPersist) { - const recoilPersistObj = JSON.parse(recoilPersist); - if (Object.keys(recoilPersistObj).includes("CurrentSection")) { - currentSectionFromPersist = recoilPersistObj.CurrentSection; + let targetCabinet = null; + for (const cluster of response.data) { + targetCabinet = cluster.cabinets.find( + (cabinet: CabinetPreviewInfo) => + cabinet.cabinetId === targetCabinetInfo?.cabinetId + ); + if (targetCabinet) break; + } + if ( + targetCabinet && + (targetCabinet.userCount !== targetCabinetInfo.lents.length || + targetCabinet.status !== targetCabinetInfo.status) + ) { + try { + let fullInfo = await axiosCabinetById(targetCabinet.cabinetId); + setTargetCabinetInfo(fullInfo.data); + } catch (error) { + console.log(error); } } - currentSectionFromPersist && - sections.includes(currentSectionFromPersist) - ? setCurrentSection(currentSectionFromPersist) - : setCurrentSection(response.data[0].section); }) .catch((error) => { console.error(error); }) .finally(() => {}); - // 내 사물함과 연장권 정보 업데이트를 위해 myInfo 요청 - try { - const { data: myInfo } = await axiosMyInfo(); - setMyInfoData(myInfo); - setUser(myInfo); - } catch (error) { - console.error(error); - } } catch (error) { console.log(error); } From 595dd61f398573573806596b92ce0b689ffd8b4c Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 18:10:58 +0900 Subject: [PATCH 199/208] =?UTF-8?q?[FE]=20FEAT:=20CabinetInfoArea=20?= =?UTF-8?q?=EC=97=90=20=ED=91=9C=EC=8B=9C=ED=95=A0=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EC=9D=84=20=EC=8B=9C=20=EC=95=88=EB=82=B4?= =?UTF-8?q?=20=EB=AC=B8=EA=B5=AC=20=EC=B6=94=EA=B0=80=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CabinetInfoArea/CabinetInfoArea.tsx | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index 35e392803..d38cd768e 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -193,7 +193,7 @@ const CabinetInfoArea: React.FC<{ {selectedCabinetInfo!.detailMessage} - {selectedCabinetInfo!.cabinetId === 0 ? "-" : expireDate} + {selectedCabinetInfo!.cabinetId === 0 ? "" : expireDate} {isMine && @@ -213,6 +213,17 @@ const CabinetInfoArea: React.FC<{ } /> )} + {!isExtensible && + selectedCabinetInfo!.cabinetId === 0 && + selectedCabinetInfo!.lentType === "PRIVATE" && ( + + + 사물함을 대여하시면 +
+ 사물함 정보가 표시됩니다. +
+
+ )} {isMine && selectedCabinetInfo.lentsLength <= 1 && selectedCabinetInfo.lentType === "SHARE" && @@ -406,6 +417,46 @@ const Animation2 = keyframes` } `; +export const DetailStyled = styled.p` + margin-top: 20px; + letter-spacing: -0.02rem; + line-height: 1.5rem; + font-size: 14px; + font-weight: 300; + white-space: break-spaces; +`; + +const ButtonWrapperStyled = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; + +const ButtonContainerStyled = styled.button` + max-width: 400px; + width: 110%; + height: 80px; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + border-radius: 10px; + margin-bottom: 15px; + &:disabled { + opacity: 0.3; + cursor: not-allowed; + } + &:last-child { + margin-bottom: 0; + } + background: var(--white); + color: var(--main-color); + border: 1px solid var(--main-color); + @media (max-height: 745px) { + margin-bottom: 8px; + } +`; + const HoverBox = styled.div<{ canUseExtendTicket?: boolean; }>` From 3f5a05a2ce3d542663a7c203b4d011d42f363fc8 Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 20:22:04 +0900 Subject: [PATCH 200/208] =?UTF-8?q?[FE]=20FEAT:=20=ED=91=9C=EC=8B=9C?= =?UTF-8?q?=ED=95=A0=20=EC=A0=95=EB=B3=B4=EA=B0=80=20=EC=97=86=EC=9D=84=20?= =?UTF-8?q?=EC=8B=9C=20=EC=B6=9C=EB=A0=A5=EB=90=98=EB=8D=98=20=EC=95=88?= =?UTF-8?q?=EB=82=B4=EB=AC=B8=EA=B5=AC=EB=A5=BC=20=EC=97=B0=EC=9E=A5?= =?UTF-8?q?=EA=B6=8C=20=EB=AF=B8=EB=B3=B4=EC=9C=A0=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/assets/images/extensionTicketGray.svg | 6 +++ .../CabinetInfoArea/CabinetInfoArea.tsx | 44 +++++++++---------- 2 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 frontend/src/assets/images/extensionTicketGray.svg diff --git a/frontend/src/assets/images/extensionTicketGray.svg b/frontend/src/assets/images/extensionTicketGray.svg new file mode 100644 index 000000000..524de2eb0 --- /dev/null +++ b/frontend/src/assets/images/extensionTicketGray.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index d38cd768e..4610569a2 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -165,18 +165,29 @@ const CabinetInfoArea: React.FC<{ /> )} - {isExtensible && - selectedCabinetInfo!.cabinetId === 0 && + {selectedCabinetInfo!.cabinetId === 0 && selectedCabinetInfo!.lentType === "PRIVATE" ? ( - { - openModal("extendModal"); - }} - text={"연장권 보유중"} - theme="line" - iconSrc="/src/assets/images/extensionTicket.svg" - iconAlt="연장권 아이콘" - /> + <> + { + openModal("extendModal"); + }} + text={isExtensible ? "연장권 보유중" : "연장권 미보유"} + theme={isExtensible ? "line" : "grayLine"} + iconSrc={ + isExtensible + ? "/src/assets/images/extensionTicket.svg" + : "/src/assets/images/extensionTicketGray.svg" + } + iconAlt="연장권 아이콘" + disabled={!isExtensible} + /> + + ) : null} {selectedCabinetInfo.status == "IN_SESSION" && ( @@ -213,17 +224,6 @@ const CabinetInfoArea: React.FC<{ } /> )} - {!isExtensible && - selectedCabinetInfo!.cabinetId === 0 && - selectedCabinetInfo!.lentType === "PRIVATE" && ( - - - 사물함을 대여하시면 -
- 사물함 정보가 표시됩니다. -
-
- )} {isMine && selectedCabinetInfo.lentsLength <= 1 && selectedCabinetInfo.lentType === "SHARE" && From e7b0886bdb12d20f1289c789419eb56ad63455f9 Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 20:23:54 +0900 Subject: [PATCH 201/208] =?UTF-8?q?[FE]=20FIX:=20=EB=8C=80=EA=B8=B0?= =?UTF-8?q?=EC=97=B4=20=EC=9E=85=EC=9E=A5=20=EC=8B=9C=20=EB=82=B4=20?= =?UTF-8?q?=EC=82=AC=EB=AC=BC=ED=95=A8=20=EC=A0=95=EB=B3=B4=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TopNavButtonGroup/TopNavButtonGroup.tsx | 71 +++++-------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx index 34aa8aea7..afd7c9d9e 100644 --- a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx +++ b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx @@ -1,25 +1,21 @@ import { useLocation, useNavigate } from "react-router-dom"; -import { useRecoilState, useSetRecoilState } from "recoil"; +import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; import styled from "styled-components"; import { currentCabinetIdState, myCabinetInfoState, targetCabinetInfoState, - targetUserInfoState, userState, } from "@/recoil/atoms"; import TopNavButton from "@/components/TopNav/TopNavButtonGroup/TopNavButton/TopNavButton"; -import { CabinetInfo, MyCabinetInfoResponseDto } from "@/types/dto/cabinet.dto"; +import { CabinetInfo } from "@/types/dto/cabinet.dto"; import { LentDto } from "@/types/dto/lent.dto"; -import { UserInfo } from "@/types/dto/user.dto"; import { UserDto } from "@/types/dto/user.dto"; import CabinetStatus from "@/types/enum/cabinet.status.enum"; import CabinetType from "@/types/enum/cabinet.type.enum"; import { axiosCabinetById, axiosDeleteCurrentBanLog, - axiosMyInfo, - axiosMyLentInfo, } from "@/api/axios/axios.custom"; import useMenu from "@/hooks/useMenu"; @@ -44,83 +40,54 @@ const getDefaultCabinetInfo = (myInfo: UserDto): CabinetInfo => ({ ] as LentDto[], statusNote: "", }); - const TopNavButtonGroup = ({ isAdmin }: { isAdmin?: boolean }) => { const { toggleCabinet, toggleMap, openCabinet, closeAll } = useMenu(); const [currentCabinetId, setCurrentCabinetId] = useRecoilState( currentCabinetIdState ); - - const setMyLentInfo = - useSetRecoilState(myCabinetInfoState); - const [targetCabinetInfo, setTargetCabinetInfo] = useRecoilState( + const setTargetCabinetInfo = useSetRecoilState( targetCabinetInfoState ); - const [myInfo, setMyInfo] = useRecoilState(userState); - const [myInfoData, setMyInfoData] = - useRecoilState(targetUserInfoState); + const myInfo = useRecoilValue(userState); + const myCabinetInfo = useRecoilValue(myCabinetInfoState); const { pathname } = useLocation(); const navigator = useNavigate(); - - const setTargetCabinetInfoToMyCabinet = async () => { + async function setTargetCabinetInfoToMyCabinet() { if (myInfo.cabinetId === null) { const defaultCabinetInfo = getDefaultCabinetInfo(myInfo); setTargetCabinetInfo(defaultCabinetInfo); setCurrentCabinetId(0); - return; - } - setCurrentCabinetId(myInfo.cabinetId); - setMyInfoData(myInfoData); + } else setCurrentCabinetId(myInfo.cabinetId); try { - const { data } = await axiosCabinetById(myInfo.cabinetId); + if (!myCabinetInfo?.cabinetId) return; + const { data } = await axiosCabinetById(myCabinetInfo.cabinetId); setTargetCabinetInfo(data); } catch (error) { console.log(error); } - }; - - const clickMyCabinet = async () => { - try { - const { data: myInfo } = await axiosMyInfo(); - setMyInfo(myInfo); - } catch (error: any) { - throw error; - } finally { - if (myInfo.cabinetId === null) { - setTargetCabinetInfoToMyCabinet(); - toggleCabinet(); - } else if (currentCabinetId !== myInfo.cabinetId) { - setTargetCabinetInfoToMyCabinet(); - openCabinet(); - } else { - toggleCabinet(); - } - try { - const { data: myLentInfo } = await axiosMyLentInfo(); - if (myLentInfo) { - setMyLentInfo(myLentInfo); - setMyInfo({ ...myInfo, cabinetId: myLentInfo.cabinetId }); - setTargetCabinetInfo(myLentInfo); - } - } catch (error) { - throw error; - } + } + const clickMyCabinet = () => { + if (myInfo.cabinetId === null) { + setTargetCabinetInfoToMyCabinet(); + toggleCabinet(); + } else if (currentCabinetId !== myInfo.cabinetId) { + setTargetCabinetInfoToMyCabinet(); + openCabinet(); + } else { + toggleCabinet(); } }; - const searchBarOn = () => { document.getElementById("searchBar")!.classList.add("on"); document.getElementById("topNavLogo")!.classList.add("pushOut"); document.getElementById("topNavButtonGroup")!.classList.add("pushOut"); document.getElementById("topNavWrap")!.classList.add("pushOut"); }; - const clickSearchButton = () => { if (!pathname.includes("search")) navigator("search"); closeAll(); searchBarOn(); }; - return ( {import.meta.env.VITE_UNBAN === "true" && ( From b8058635ca039f5af8398776d0b6fb0bc0d4be56 Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 21:39:20 +0900 Subject: [PATCH 202/208] =?UTF-8?q?[FE]=20FIX:=20=EC=82=AC=EB=AC=BC?= =?UTF-8?q?=ED=95=A8=20=EB=8C=80=EC=97=AC=20=EC=8B=9C,=20=EB=B0=98?= =?UTF-8?q?=EB=82=A9=20=ED=9B=84=20myCabinetInfo=20=EA=B0=80=20=EC=A0=9C?= =?UTF-8?q?=EB=8C=80=EB=A1=9C=20=ED=91=9C=EC=8B=9C=EB=90=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95#13?= =?UTF-8?q?74?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CabinetInfoArea.container.tsx | 4 +- .../TopNavButtonGroup/TopNavButtonGroup.tsx | 47 +++++++++++++++---- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx index 7440b9896..7891009b5 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.container.tsx @@ -313,8 +313,8 @@ const CabinetInfoAreaContainer = (): JSX.Element => { closeCabinet={closeCabinet} expireDate={setExpireDate(cabinetViewData?.expireDate)} isMine={ - (myCabinetInfo?.cabinetId === cabinetViewData?.cabinetId || - myCabinetInfo?.cabinetId === 0) && + myCabinetInfo?.cabinetId === cabinetViewData?.cabinetId && + myCabinetInfo?.cabinetId !== 0 && cabinetViewData?.status !== "AVAILABLE" } isAvailable={ diff --git a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx index afd7c9d9e..1ffa969e7 100644 --- a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx +++ b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx @@ -48,32 +48,63 @@ const TopNavButtonGroup = ({ isAdmin }: { isAdmin?: boolean }) => { const setTargetCabinetInfo = useSetRecoilState( targetCabinetInfoState ); - const myInfo = useRecoilValue(userState); - const myCabinetInfo = useRecoilValue(myCabinetInfoState); + const [myInfo, setMyInfo] = useRecoilState(userState); + const [myCabinetInfo, setMyCabinetInfo] = useRecoilState(myCabinetInfoState); const { pathname } = useLocation(); const navigator = useNavigate(); + const defaultCabinetInfo = getDefaultCabinetInfo(myInfo); + const resetCabinetInfo = () => { + setMyCabinetInfo({ + ...defaultCabinetInfo, + memo: "", + shareCode: 0, + previousUserName: "", + }); + setTargetCabinetInfo(defaultCabinetInfo); + setCurrentCabinetId(0); + }; async function setTargetCabinetInfoToMyCabinet() { - if (myInfo.cabinetId === null) { - const defaultCabinetInfo = getDefaultCabinetInfo(myInfo); - setTargetCabinetInfo(defaultCabinetInfo); - setCurrentCabinetId(0); + if (myInfo.cabinetId === null && !myCabinetInfo?.cabinetId) { + resetCabinetInfo(); } else setCurrentCabinetId(myInfo.cabinetId); + setMyInfo((prev) => ({ ...prev, cabinetId: null })); try { if (!myCabinetInfo?.cabinetId) return; const { data } = await axiosCabinetById(myCabinetInfo.cabinetId); - setTargetCabinetInfo(data); + if (data.lents.length === 0 && myInfo.cabinetId !== null) { + resetCabinetInfo(); + setMyInfo((prev) => ({ ...prev, cabinetId: null })); + } else { + setMyCabinetInfo((prev) => ({ + ...data, + memo: "", + shareCode: prev.shareCode, + previousUserName: prev.previousUserName, + })); + const doesNameExist = data.lents.some( + (lent: LentDto) => lent.name === myInfo.name + ); + if (doesNameExist) { + setTargetCabinetInfo(data); + setCurrentCabinetId(data.cabinetId); + setMyInfo((prev) => ({ ...prev, cabinetId: data.cabinetId })); + } else resetCabinetInfo(); + } } catch (error) { console.log(error); } } const clickMyCabinet = () => { - if (myInfo.cabinetId === null) { + if (myInfo.cabinetId === null && !myCabinetInfo?.cabinetId) { + console.log("clickMyCabinet myInfo.cabinetId === null"); setTargetCabinetInfoToMyCabinet(); toggleCabinet(); } else if (currentCabinetId !== myInfo.cabinetId) { + console.log("clickMyCabinet currentCabinetId !== myInfo.cabinetId"); setTargetCabinetInfoToMyCabinet(); openCabinet(); } else { + console.log("clickMyCabinet else"); toggleCabinet(); } }; From 2db6444413e79ecd722f75ecbdcd087649b0972b Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 22:06:09 +0900 Subject: [PATCH 203/208] =?UTF-8?q?[FE]=20FIX:=20=EA=B3=B5=EC=9C=A0?= =?UTF-8?q?=EC=82=AC=EB=AC=BC=ED=95=A8=20=EB=8B=A8=EB=8F=85=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EC=8B=9C=20=ED=98=B8=EB=B2=84=EB=A7=81=20=EB=9C=A8?= =?UTF-8?q?=EB=8A=94=20=EC=A1=B0=EA=B1=B4=20=EC=88=98=EC=A0=95=20#1374?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx index 4610569a2..f130e184d 100644 --- a/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx +++ b/frontend/src/components/CabinetInfoArea/CabinetInfoArea.tsx @@ -225,6 +225,7 @@ const CabinetInfoArea: React.FC<{ /> )} {isMine && + isExtensible && selectedCabinetInfo.lentsLength <= 1 && selectedCabinetInfo.lentType === "SHARE" && selectedCabinetInfo.status !== "IN_SESSION" && ( From ced4b52d22a3bea4523e0b7d63f22bbfee4cd812 Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 22:33:42 +0900 Subject: [PATCH 204/208] =?UTF-8?q?[FE]=20FIX:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=9A=A9=20console.log=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx index 1ffa969e7..09303d52c 100644 --- a/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx +++ b/frontend/src/components/TopNav/TopNavButtonGroup/TopNavButtonGroup.tsx @@ -96,15 +96,12 @@ const TopNavButtonGroup = ({ isAdmin }: { isAdmin?: boolean }) => { } const clickMyCabinet = () => { if (myInfo.cabinetId === null && !myCabinetInfo?.cabinetId) { - console.log("clickMyCabinet myInfo.cabinetId === null"); setTargetCabinetInfoToMyCabinet(); toggleCabinet(); } else if (currentCabinetId !== myInfo.cabinetId) { - console.log("clickMyCabinet currentCabinetId !== myInfo.cabinetId"); setTargetCabinetInfoToMyCabinet(); openCabinet(); } else { - console.log("clickMyCabinet else"); toggleCabinet(); } }; From e3fd2dc04d5f9f5fb61a85c85a93fbc73a1d6ef2 Mon Sep 17 00:00:00 2001 From: jusohn Date: Mon, 4 Sep 2023 22:38:56 +0900 Subject: [PATCH 205/208] =?UTF-8?q?[FE]=20FIX:=20OverduePenaltyModal=20?= =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Modals/ExtendModal/ExtendModal.tsx | 2 +- frontend/src/components/Modals/Modal.tsx | 2 +- .../Modals/OverduePenaltyModal/OverduePenaltyModal.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Modals/ExtendModal/ExtendModal.tsx b/frontend/src/components/Modals/ExtendModal/ExtendModal.tsx index 81da307bf..a0127fe84 100644 --- a/frontend/src/components/Modals/ExtendModal/ExtendModal.tsx +++ b/frontend/src/components/Modals/ExtendModal/ExtendModal.tsx @@ -103,7 +103,7 @@ const ExtendModal: React.FC<{ }; const extendModalContents: IModalContents = { - type: myInfo.cabinetId === null ? "panaltyBtn" : "hasProceedBtn", + type: myInfo.cabinetId === null ? "penaltyBtn" : "hasProceedBtn", icon: checkIcon, title: getModalTitle(myInfo.cabinetId), detail: getModalDetail(myInfo.cabinetId), diff --git a/frontend/src/components/Modals/Modal.tsx b/frontend/src/components/Modals/Modal.tsx index 56b52f72a..5f8e3c50c 100644 --- a/frontend/src/components/Modals/Modal.tsx +++ b/frontend/src/components/Modals/Modal.tsx @@ -89,7 +89,7 @@ const Modal: React.FC<{ modalContents: IModalContents }> = (props) => { /> )} - {type === "panaltyBtn" && ( + {type === "penaltyBtn" && (