From b900d454fb392a795a4298142ccc12a743d7e6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Thu, 30 Jan 2025 19:38:03 +0900 Subject: [PATCH 01/18] =?UTF-8?q?style=20:=20=EA=B2=8C=EC=8B=9C=ED=8C=90?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20ui=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style : 게시판 수정 모달창 ui 구현 --- src/components/modals/ModBoardModal/index.tsx | 115 +++++++++++ src/components/modals/ModBoardModal/style.ts | 192 ++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 src/components/modals/ModBoardModal/index.tsx create mode 100644 src/components/modals/ModBoardModal/style.ts diff --git a/src/components/modals/ModBoardModal/index.tsx b/src/components/modals/ModBoardModal/index.tsx new file mode 100644 index 0000000..cac5cbc --- /dev/null +++ b/src/components/modals/ModBoardModal/index.tsx @@ -0,0 +1,115 @@ +import React, { useState } from 'react'; +import { + ModalOverlay, + ModalContent, + ModalHeader, + InputFieldWrapper, + InputField, + EmailList, + ButtonWrapper, + SubmitButton, + Line, + ErrorMessage, + SuccessMessage, +} from './style'; +import { BsXLg } from 'react-icons/bs'; + +const EditBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { + // 더미 데이터로 초기값 설정 + const [boardName, setBoardName] = useState('9oorm_KDT'); + const [email, setEmail] = useState(''); + const [emailList, setEmailList] = useState([ + 'esder1310@hufs.ac.kr', + 'imi21123@gmail.com', + ]); + const [emailError, setEmailError] = useState(false); + const [emailSuccess, setEmailSuccess] = useState(false); + + const validateEmail = (email: string): boolean => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + e.preventDefault(); + if (validateEmail(email)) { + if (!emailList.includes(email)) { + setEmailList([...emailList, email]); + setEmailSuccess(true); + setEmailError(false); + setEmail(''); + } else { + setEmailError(true); + setEmailSuccess(false); + } + } else { + setEmailError(true); + setEmailSuccess(false); + } + } + }; + + const handleRemoveEmail = (targetEmail: string) => { + setEmailList(emailList.filter((item) => item !== targetEmail)); + }; + + const handleEditBoard = () => { + console.log('수정된 게시판 이름:', boardName); + console.log('수정된 참여자 이메일 목록:', emailList); + onClose(); // 모달 닫기 + }; + + return ( + + + +

게시판 수정하기

+ +
+ + setBoardName(e.target.value)} + /> +

참여자 초대하기

+ + setEmail(e.target.value)} + onKeyDown={handleKeyDown} + style={{ + borderColor: emailError ? 'var(--red)' : 'var(--light-gray)', + }} + /> + {emailSuccess && ( + 초대가 완료되었습니다. + )} + {emailError && ( + 틀린 이메일이거나 없는 이메일입니다. + )} + + + {emailList.map((item, index) => ( +
+ {item} + handleRemoveEmail(item)} + /> +
+ ))} +
+ + 게시판 수정 + +
+
+ ); +}; + +export default EditBoardModal; diff --git a/src/components/modals/ModBoardModal/style.ts b/src/components/modals/ModBoardModal/style.ts new file mode 100644 index 0000000..3deb3f0 --- /dev/null +++ b/src/components/modals/ModBoardModal/style.ts @@ -0,0 +1,192 @@ +import styled from '@emotion/styled'; + +export const ModalOverlay = styled.div` + display: flex; + position: fixed; + top: 0; + left: 7.875rem; + width: 100%; + min-height: 100vh; + background: var(--modal-bg); + justify-content: center; + align-items: center; +`; + +export const ModalContent = styled.div` + display: flex; + flex-direction: column; + flex-shrink: 0; + border-radius: 0.9375rem; + border: 1px solid var(--gray); + background: var(--background); + padding: 2rem; + box-shadow: + 0px 0px 4px 0px var(--light-gray) inset, + 0px 0px 4px 0px var(--black); + + h3 { + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.375rem; + font-style: normal; + font-weight: 700; + line-height: normal; + margin-top: 1.69rem; + margin-bottom: 1.06rem; + } +`; + +export const ModalHeader = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.37rem; + + h2 { + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.75rem; + font-style: normal; + font-weight: 700; + line-height: normal; + } + + .CloseButton { + width: 1.5rem; + height: 1.5rem; + flex-shrink: 0; + background: none; + border: none; + cursor: pointer; + color: var(--light-gray); + } +`; + +export const Line = styled.div` + width: 100%; + height: 0.125rem; + flex-shrink: 0; + border-radius: 3.125rem; + background-color: var(--gray); + margin-bottom: 1.37rem; +`; + +export const InputFieldWrapper = styled.div` + position: relative; +`; + +export const InputField = styled.input` + width: 34.875rem; + height: 2rem; + flex-shrink: 0; + background: var(--input); + border-radius: 0.4375rem; + border: 3px solid var(--light-gray); + backdrop-filter: blur(2px); + padding: 0.81rem 1.3rem; + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.125rem; + font-style: normal; + font-weight: 400; + line-height: normal; +`; + +export const ErrorMessage = styled.div` + color: var(--red); + text-align: right; + font-family: 'Pretendard'; + font-size: 0.625rem; + font-style: normal; + font-weight: 400; + line-height: normal; + position: absolute; + top: -1.5rem; + right: 0; +`; + +export const SuccessMessage = styled.div` + color: var(--light-gray); + text-align: right; + font-family: 'Pretendard'; + font-size: 0.625rem; + font-style: normal; + font-weight: 400; + line-height: normal; + position: absolute; + top: -1.5rem; + right: 0; +`; + +export const EmailList = styled.div` + display: flex; /* flex container 설정 */ + flex-direction: row; /* 가로 정렬 */ + gap: 0.5rem; /* 아이템 간 간격 */ + flex-wrap: wrap; /* 아이템이 넘칠 경우 줄바꿈 */ + margin-top: 0.88rem; + + .email-item { + width: 10.625rem; + height: 1.75rem; + flex-shrink: 0; + border: 1px solid var(--light-gray); + border-radius: 1.875rem; + background: var(--input); + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.69rem 0.88rem; + color: var(--light-gray); + font-family: 'Pretendard'; + font-size: 0.875rem; + font-style: normal; + font-weight: 400; + line-height: normal; + } + + .CloseEmailButton { + width: 0.9375rem; + height: 0.9375rem; + flex-shrink: 0; + background: none; + border: none; + cursor: pointer; + color: var(--light-gray); + font-family: 'Pretendard'; + font-size: 0.875rem; + font-style: normal; + font-weight: 400; + line-height: normal; + } +`; + +export const ButtonWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + margin-top: 5.94rem; +`; + +export const SubmitButton = styled.button` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 20.6875rem; + height: 4.0625rem; + flex-shrink: 0; + border-radius: 0.4375rem; + background: var(--input); + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.25rem; + font-style: normal; + font-weight: 700; + line-height: normal; + border: none; + cursor: pointer; + + &:hover { + background: var(--black); + } +`; From 5ac9e2eb52a39365aa27e7523f31c380c9045c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Thu, 30 Jan 2025 19:53:20 +0900 Subject: [PATCH 02/18] =?UTF-8?q?style=20:=20modal=EC=B0=BD=20props=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 style : modal창 props 추가 --- .../modals/{ModBoardModal => EditBoardModal}/index.tsx | 0 .../modals/{ModBoardModal => EditBoardModal}/style.ts | 0 src/models/modal.ts | 4 ++++ 3 files changed, 4 insertions(+) rename src/components/modals/{ModBoardModal => EditBoardModal}/index.tsx (100%) rename src/components/modals/{ModBoardModal => EditBoardModal}/style.ts (100%) create mode 100644 src/models/modal.ts diff --git a/src/components/modals/ModBoardModal/index.tsx b/src/components/modals/EditBoardModal/index.tsx similarity index 100% rename from src/components/modals/ModBoardModal/index.tsx rename to src/components/modals/EditBoardModal/index.tsx diff --git a/src/components/modals/ModBoardModal/style.ts b/src/components/modals/EditBoardModal/style.ts similarity index 100% rename from src/components/modals/ModBoardModal/style.ts rename to src/components/modals/EditBoardModal/style.ts diff --git a/src/models/modal.ts b/src/models/modal.ts new file mode 100644 index 0000000..25e3b5e --- /dev/null +++ b/src/models/modal.ts @@ -0,0 +1,4 @@ +export interface ModalProps { + isOpen: boolean; + onClose: () => void; +} From 5ff6acbb454860cc587ba8887e6b1794242a7196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Thu, 30 Jan 2025 20:38:45 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat,=20style=20:=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=ED=8C=90=20=ED=97=A4=EB=8D=94=EC=97=90=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=ED=8C=90=20=EC=88=98=EC=A0=95=20=EB=AA=A8=EB=8B=AC=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0,=20react-modal=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat, style : 게시판 헤더에 게시판 수정 모달 연결, react-modal 설치 --- package-lock.json | 51 ++++++++++++++++++- package.json | 2 + .../modals/EditBoardModal/index.tsx | 14 +++-- src/components/modals/EditBoardModal/style.ts | 35 +++++++++---- src/models/modal.ts | 2 +- 5 files changed, 86 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a38c0f..f34a0b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-icons": "^5.4.0", + "react-modal": "^3.16.3", "react-router-dom": "^7.1.1", "rollup-plugin-polyfill-node": "^0.13.0", "vite-plugin-node-polyfills": "^0.23.0" @@ -30,6 +31,7 @@ "@types/axios": "^0.14.4", "@types/react": "^18.3.18", "@types/react-dom": "^18.3.5", + "@types/react-modal": "^3.16.3", "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^8.20.0", "@typescript-eslint/parser": "^8.20.0", @@ -1635,6 +1637,16 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/react-modal": { + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.3.tgz", + "integrity": "sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-router": { "version": "5.1.20", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", @@ -3501,6 +3513,12 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==", + "license": "BSD-3-Clause" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5063,7 +5081,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5468,7 +5485,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -5602,6 +5618,28 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, + "node_modules/react-modal": { + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.3.tgz", + "integrity": "sha512-yCYRJB5YkeQDQlTt17WGAgFJ7jr2QYcWa1SHqZ3PluDmnKJ/7+tVU+E6uKyZ0nODaeEj+xCpK4LcSnKXLMC0Nw==", + "license": "MIT", + "dependencies": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19", + "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19" + } + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -6773,6 +6811,15 @@ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 61da47b..a0443eb 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-icons": "^5.4.0", + "react-modal": "^3.16.3", "react-router-dom": "^7.1.1", "rollup-plugin-polyfill-node": "^0.13.0", "vite-plugin-node-polyfills": "^0.23.0" @@ -33,6 +34,7 @@ "@types/axios": "^0.14.4", "@types/react": "^18.3.18", "@types/react-dom": "^18.3.5", + "@types/react-modal": "^3.16.3", "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^8.20.0", "@typescript-eslint/parser": "^8.20.0", diff --git a/src/components/modals/EditBoardModal/index.tsx b/src/components/modals/EditBoardModal/index.tsx index cac5cbc..5345fb4 100644 --- a/src/components/modals/EditBoardModal/index.tsx +++ b/src/components/modals/EditBoardModal/index.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; +import Modal from 'react-modal'; // react-modal import import { - ModalOverlay, + customModalStyles, ModalContent, ModalHeader, InputFieldWrapper, @@ -13,8 +14,9 @@ import { SuccessMessage, } from './style'; import { BsXLg } from 'react-icons/bs'; +import { BoardModalProps } from '../../../models/modal'; -const EditBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { +const EditBoardModal: React.FC = ({ isOpen, onClose }) => { // 더미 데이터로 초기값 설정 const [boardName, setBoardName] = useState('9oorm_KDT'); const [email, setEmail] = useState(''); @@ -61,7 +63,11 @@ const EditBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { }; return ( - +

게시판 수정하기

@@ -108,7 +114,7 @@ const EditBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { 게시판 수정
-
+ ); }; diff --git a/src/components/modals/EditBoardModal/style.ts b/src/components/modals/EditBoardModal/style.ts index 3deb3f0..0ef664c 100644 --- a/src/components/modals/EditBoardModal/style.ts +++ b/src/components/modals/EditBoardModal/style.ts @@ -1,16 +1,29 @@ import styled from '@emotion/styled'; -export const ModalOverlay = styled.div` - display: flex; - position: fixed; - top: 0; - left: 7.875rem; - width: 100%; - min-height: 100vh; - background: var(--modal-bg); - justify-content: center; - align-items: center; -`; +export const customModalStyles = { + content: { + width: '40rem', + margin: 'auto', + borderRadius: '10px', + padding: '2rem', + background: 'var(--background)', + }, + overlay: { + backgroundColor: 'rgba(0, 0, 0, 0.5)', + }, +}; + +//export const ModalOverlay = styled.div` +// display: flex; +// position: fixed; +// top: 0; +// left: 7.875rem; +// width: 100%; +// min-height: 100vh; +// background: var(--modal-bg); +// justify-content: center; +// align-items: center; +//`; export const ModalContent = styled.div` display: flex; diff --git a/src/models/modal.ts b/src/models/modal.ts index 25e3b5e..fb6c037 100644 --- a/src/models/modal.ts +++ b/src/models/modal.ts @@ -1,4 +1,4 @@ -export interface ModalProps { +export interface BoardModalProps { isOpen: boolean; onClose: () => void; } From 1f839c050fe9bb2253512dad5dd92cb14cc1a651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Thu, 30 Jan 2025 20:40:54 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat=20:=20=EA=B2=8C=EC=8B=9C=ED=8C=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=AA=A8=EB=8B=AC=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : 게시판 생성 모달 연결 --- src/components/board/Header.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/board/Header.tsx b/src/components/board/Header.tsx index d338230..81add39 100644 --- a/src/components/board/Header.tsx +++ b/src/components/board/Header.tsx @@ -1,16 +1,14 @@ -import React from 'react'; +import React, { useState } from 'react'; import styled from '@emotion/styled'; import { BsTrashFill, BsThreeDotsVertical } from 'react-icons/bs'; +import EditBoardModal from '../modals/EditBoardModal'; interface BoardHeader { boardName: string; } const Header: React.FC = ({ boardName }) => { - const handleEditButton = () => { - /* 추후 api 연동 */ - alert('수정하기 버튼을 눌렀습니다.'); - }; + const [isEditBoardModalOpen, setEditBoardModalOpen] = useState(false); const handleDeleteButton = () => { /* 추후 api 연동 */ @@ -28,10 +26,16 @@ const Header: React.FC = ({ boardName }) => { <Board>{boardName}</Board> - + setEditBoardModalOpen(true)} /> 수업 생성 + + {/* 모달 컴포넌트 */} + setEditBoardModalOpen(false)} + /> ); }; From c4853c009642e810b04deb9d3abc27a2baccb4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 00:39:45 +0900 Subject: [PATCH 05/18] =?UTF-8?q?style=20:=20react-modal=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0,=20ModalOverlay=20=EC=9E=AC=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style : react-modal 제거, ModalOverlay 재사용 --- .../modals/EditBoardModal/index.tsx | 19 +++++----- src/components/modals/EditBoardModal/style.ts | 35 ++++++------------- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/components/modals/EditBoardModal/index.tsx b/src/components/modals/EditBoardModal/index.tsx index 5345fb4..d2fde1c 100644 --- a/src/components/modals/EditBoardModal/index.tsx +++ b/src/components/modals/EditBoardModal/index.tsx @@ -1,7 +1,6 @@ import React, { useState } from 'react'; -import Modal from 'react-modal'; // react-modal import import { - customModalStyles, + ModalOverlay, ModalContent, ModalHeader, InputFieldWrapper, @@ -14,7 +13,7 @@ import { SuccessMessage, } from './style'; import { BsXLg } from 'react-icons/bs'; -import { BoardModalProps } from '../../../models/modal'; +import { BoardModalProps } from '../../../models/Modal'; const EditBoardModal: React.FC = ({ isOpen, onClose }) => { // 더미 데이터로 초기값 설정 @@ -59,15 +58,15 @@ const EditBoardModal: React.FC = ({ isOpen, onClose }) => { const handleEditBoard = () => { console.log('수정된 게시판 이름:', boardName); console.log('수정된 참여자 이메일 목록:', emailList); - onClose(); // 모달 닫기 + onClose(); }; + if (!isOpen) { + return null; // 모달이 열려있지 않으면 렌더링하지 않음 + } + return ( - +

게시판 수정하기

@@ -114,7 +113,7 @@ const EditBoardModal: React.FC = ({ isOpen, onClose }) => { 게시판 수정
-
+ ); }; diff --git a/src/components/modals/EditBoardModal/style.ts b/src/components/modals/EditBoardModal/style.ts index 0ef664c..3deb3f0 100644 --- a/src/components/modals/EditBoardModal/style.ts +++ b/src/components/modals/EditBoardModal/style.ts @@ -1,29 +1,16 @@ import styled from '@emotion/styled'; -export const customModalStyles = { - content: { - width: '40rem', - margin: 'auto', - borderRadius: '10px', - padding: '2rem', - background: 'var(--background)', - }, - overlay: { - backgroundColor: 'rgba(0, 0, 0, 0.5)', - }, -}; - -//export const ModalOverlay = styled.div` -// display: flex; -// position: fixed; -// top: 0; -// left: 7.875rem; -// width: 100%; -// min-height: 100vh; -// background: var(--modal-bg); -// justify-content: center; -// align-items: center; -//`; +export const ModalOverlay = styled.div` + display: flex; + position: fixed; + top: 0; + left: 7.875rem; + width: 100%; + min-height: 100vh; + background: var(--modal-bg); + justify-content: center; + align-items: center; +`; export const ModalContent = styled.div` display: flex; From 579251e06c9b36aa4f1e681f5cdcc2a1003d3138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 01:04:08 +0900 Subject: [PATCH 06/18] =?UTF-8?q?style=20:=20addboardmodal=EC=97=90=20prop?= =?UTF-8?q?s=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style : addboardmodal에 props 적용 --- src/components/modals/AddBoardModal/index.tsx | 47 +++++++++++-------- .../modals/DeleteBoardModal/index.tsx | 0 .../modals/DeleteBoardModal/style.ts | 0 3 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 src/components/modals/DeleteBoardModal/index.tsx create mode 100644 src/components/modals/DeleteBoardModal/style.ts diff --git a/src/components/modals/AddBoardModal/index.tsx b/src/components/modals/AddBoardModal/index.tsx index eb5953d..a5ec66c 100644 --- a/src/components/modals/AddBoardModal/index.tsx +++ b/src/components/modals/AddBoardModal/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState } from 'react'; import { ModalOverlay, ModalContent, @@ -11,12 +11,13 @@ import { Line, ErrorMessage, SuccessMessage, -} from "./style"; -import { BsXLg } from "react-icons/bs"; +} from './style'; +import { BsXLg } from 'react-icons/bs'; +import { BoardModalProps } from '../../../models/Modal'; -const AddBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { - const [boardName, setBoardName] = useState(""); - const [email, setEmail] = useState(""); +const AddBoardModal: React.FC = ({ onClose }) => { + const [boardName, setBoardName] = useState(''); + const [email, setEmail] = useState(''); const [emailList, setEmailList] = useState([]); const [emailError, setEmailError] = useState(false); const [emailSuccess, setEmailSuccess] = useState(false); @@ -26,16 +27,15 @@ const AddBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { return emailRegex.test(email); }; - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { + if (e.key === 'Enter') { e.preventDefault(); // 기본 엔터 동작 방지 if (validateEmail(email)) { if (!emailList.includes(email)) { setEmailList([...emailList, email]); setEmailSuccess(true); setEmailError(false); - setEmail(""); // 입력 초기화 + setEmail(''); // 입력 초기화 } else { setEmailError(true); setEmailSuccess(false); @@ -52,8 +52,8 @@ const AddBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { }; const handleCreateBoard = () => { - console.log("게시판 이름:", boardName); - console.log("참여자 이메일 목록:", emailList); + console.log('게시판 이름:', boardName); + console.log('참여자 이메일 목록:', emailList); onClose(); // 모달 닫기 }; @@ -61,15 +61,15 @@ const AddBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { -

게시판 생성하기

- +

게시판 생성하기

+
setBoardName(e.target.value)} + onChange={(e) => setBoardName(e.target.value)} />

참여자 초대하기

@@ -80,22 +80,29 @@ const AddBoardModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { onChange={(e) => setEmail(e.target.value)} onKeyDown={handleKeyDown} style={{ - borderColor: emailError ? "var(--red)" : "var(--light-gray)", + borderColor: emailError ? 'var(--red)' : 'var(--light-gray)', }} /> - {emailSuccess && 초대가 완료되었습니다.} - {emailError && 틀린 이메일이거나 없는 이메일입니다.} + {emailSuccess && ( + 초대가 완료되었습니다. + )} + {emailError && ( + 틀린 이메일이거나 없는 이메일입니다. + )} {emailList.map((item, index) => (
{item} - handleRemoveEmail(item)} /> + handleRemoveEmail(item)} + />
))} -
+ - 게시판 생성 + 게시판 생성
diff --git a/src/components/modals/DeleteBoardModal/index.tsx b/src/components/modals/DeleteBoardModal/index.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/modals/DeleteBoardModal/style.ts b/src/components/modals/DeleteBoardModal/style.ts new file mode 100644 index 0000000..e69de29 From 0abac9a82199c83131896a49d6a11dbc2f4fe3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 01:33:46 +0900 Subject: [PATCH 07/18] =?UTF-8?q?style=20:=20=EA=B2=8C=EC=8B=9C=ED=8C=90?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20=EB=AA=A8=EB=8B=AC=20UI=20=EC=A0=9C?= =?UTF-8?q?=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style : 게시판 삭제 모달 UI 제작 --- .../modals/DeleteBoardModal/index.tsx | 53 ++++++++ .../modals/DeleteBoardModal/style.ts | 120 ++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/src/components/modals/DeleteBoardModal/index.tsx b/src/components/modals/DeleteBoardModal/index.tsx index e69de29..c8d7514 100644 --- a/src/components/modals/DeleteBoardModal/index.tsx +++ b/src/components/modals/DeleteBoardModal/index.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { + ModalOverlay, + ModalContent, + ModalHeader, + Line, + Body, + ButtonWrapper, + SubmitButton, +} from './style'; +import { BsXLg } from 'react-icons/bs'; +import { BoardModalProps } from '../../../models/Modal'; + +const DeleteBoardModal: React.FC = ({ isOpen, onClose }) => { + // 더미 데이터 + const dummyData = { + boardName: '9oorm_KDT', // 삭제할 게시판 이름 + }; + + // 삭제 버튼 클릭 핸들러 + const handleDeleteBoard = () => { + console.log(`게시판 "${dummyData.boardName}"가 삭제되었습니다.`); + onClose(); // 모달 닫기 + }; + if (!isOpen) { + return null; // 모달이 열려있지 않으면 렌더링하지 않음 + } + + return ( + + + +

게시판 삭제하기

+ +
+ + +

boardName={dummyData.boardName}

+

+ 해당 게시판을 삭제하시겠습니까? +
+ 삭제한 게시판은 복구할 수 없습니다. +

+ + + 게시판 삭제 + +
+
+ ); +}; + +export default DeleteBoardModal; diff --git a/src/components/modals/DeleteBoardModal/style.ts b/src/components/modals/DeleteBoardModal/style.ts index e69de29..b9be7da 100644 --- a/src/components/modals/DeleteBoardModal/style.ts +++ b/src/components/modals/DeleteBoardModal/style.ts @@ -0,0 +1,120 @@ +import styled from '@emotion/styled'; + +export const ModalOverlay = styled.div` + display: flex; + position: fixed; + top: 0; + left: 7.875rem; + width: 100%; + min-height: 100vh; + background: var(--modal-bg); + justify-content: center; + align-items: center; +`; + +export const ModalContent = styled.div` + display: flex; + flex-direction: column; + flex-shrink: 0; + border-radius: 0.9375rem; + border: 1px solid var(--gray); + background: var(--background); + padding: 2rem; + box-shadow: + 0px 0px 4px 0px var(--light-gray) inset, + 0px 0px 4px 0px var(--black); +`; + +export const ModalHeader = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.37rem; + + h2 { + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.75rem; + font-style: normal; + font-weight: 700; + line-height: normal; + } + + .CloseButton { + width: 1.5rem; + height: 1.5rem; + flex-shrink: 0; + background: none; + border: none; + cursor: pointer; + color: var(--light-gray); + } +`; + +export const Line = styled.div` + width: 100%; + height: 0.125rem; + flex-shrink: 0; + border-radius: 3.125rem; + background-color: var(--gray); + margin-bottom: 5.19rem; +`; + +export const Body = styled.div` + margin-top: 3.31rem; + display: flex; + justify-content: space-between; + align-items: center; + + h1 { + color: var(--red); + text-shadow: 0px 0px 4px var(--black); + font-family: 'Pretendard'; + font-size: 2.1875rem; + font-style: normal; + font-weight: 700; + line-height: normal; + } + + h3 { + color: var(--white); + text-align: center; + font-family: 'Pretendard'; + font-size: 1.5rem; + font-style: normal; + font-weight: 700; + line-height: normal; + gap: 0.81rem; + } +`; + +export const ButtonWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + margin-top: 6.25rem; +`; + +export const SubmitButton = styled.button` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 20.6875rem; + height: 4.0625rem; + flex-shrink: 0; + border-radius: 0.4375rem; + background: var(--input); + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.25rem; + font-style: normal; + font-weight: 700; + line-height: normal; + border: none; + cursor: pointer; + + &:hover { + background: var(--black); + } +`; From 90f6b992b96a64d3932e053f56a1d0c4feb8515d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 01:37:50 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat=20:=20=EA=B2=8C=EC=8B=9C=ED=8C=90=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=EC=97=90=20=EA=B2=8C=EC=8B=9C=ED=8C=90=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=AA=A8=EB=8B=AC=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : 게시판 헤더에 게시판 삭제 모달 연결 --- src/components/board/Header.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/board/Header.tsx b/src/components/board/Header.tsx index 81add39..136a1b2 100644 --- a/src/components/board/Header.tsx +++ b/src/components/board/Header.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import styled from '@emotion/styled'; import { BsTrashFill, BsThreeDotsVertical } from 'react-icons/bs'; import EditBoardModal from '../modals/EditBoardModal'; +import DeleteBoardModal from '../modals/DeleteBoardModal'; interface BoardHeader { boardName: string; @@ -9,11 +10,7 @@ interface BoardHeader { const Header: React.FC = ({ boardName }) => { const [isEditBoardModalOpen, setEditBoardModalOpen] = useState(false); - - const handleDeleteButton = () => { - /* 추후 api 연동 */ - alert('삭제하기 버튼을 눌렀습니다.'); - }; + const [isDeleteBoardModalOpen, setDeleteBoardModalOpen] = useState(false); const handleCreateButton = () => { /* 추후 api 연동 */ @@ -27,7 +24,7 @@ const Header: React.FC = ({ boardName }) => { {boardName} setEditBoardModalOpen(true)} /> - + setDeleteBoardModalOpen(true)} /> 수업 생성 @@ -36,6 +33,10 @@ const Header: React.FC = ({ boardName }) => { isOpen={isEditBoardModalOpen} onClose={() => setEditBoardModalOpen(false)} /> + setDeleteBoardModalOpen(false)} + /> ); }; From f94010ca3787a4653753872e4cf992c36b7103f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 01:55:38 +0900 Subject: [PATCH 09/18] =?UTF-8?q?style=20:=20=EA=B2=8C=EC=8B=9C=ED=8C=90?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=ED=95=98=EA=B8=B0=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?css=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style : 게시판 삭제하기 모달 css 변경 --- src/components/modals/DeleteBoardModal/index.tsx | 2 +- src/components/modals/DeleteBoardModal/style.ts | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/modals/DeleteBoardModal/index.tsx b/src/components/modals/DeleteBoardModal/index.tsx index c8d7514..1b0928f 100644 --- a/src/components/modals/DeleteBoardModal/index.tsx +++ b/src/components/modals/DeleteBoardModal/index.tsx @@ -35,7 +35,7 @@ const DeleteBoardModal: React.FC = ({ isOpen, onClose }) => { -

boardName={dummyData.boardName}

+

{dummyData.boardName}

해당 게시판을 삭제하시겠습니까?
diff --git a/src/components/modals/DeleteBoardModal/style.ts b/src/components/modals/DeleteBoardModal/style.ts index b9be7da..1a10b27 100644 --- a/src/components/modals/DeleteBoardModal/style.ts +++ b/src/components/modals/DeleteBoardModal/style.ts @@ -14,6 +14,8 @@ export const ModalOverlay = styled.div` export const ModalContent = styled.div` display: flex; + min-width: 36rem; + flex-shrink: 0; flex-direction: column; flex-shrink: 0; border-radius: 0.9375rem; @@ -61,10 +63,10 @@ export const Line = styled.div` `; export const Body = styled.div` - margin-top: 3.31rem; display: flex; - justify-content: space-between; + justify-content: center; align-items: center; + flex-direction: column; h1 { color: var(--red); @@ -74,6 +76,7 @@ export const Body = styled.div` font-style: normal; font-weight: 700; line-height: normal; + margin-bottom: 3.31rem; } h3 { @@ -83,8 +86,7 @@ export const Body = styled.div` font-size: 1.5rem; font-style: normal; font-weight: 700; - line-height: normal; - gap: 0.81rem; + line-height: 2.81rem; } `; @@ -92,7 +94,7 @@ export const ButtonWrapper = styled.div` display: flex; justify-content: center; align-items: center; - margin-top: 6.25rem; + margin-top: 5.25rem; `; export const SubmitButton = styled.button` @@ -113,6 +115,7 @@ export const SubmitButton = styled.button` line-height: normal; border: none; cursor: pointer; + margin-bottom: 0.5rem; &:hover { background: var(--black); From 066d6d745ed6cd79d9628ee3b2600d90480c4d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 02:32:27 +0900 Subject: [PATCH 10/18] =?UTF-8?q?chore=20:=20=EB=B9=8C=EB=93=9C=20type=20?= =?UTF-8?q?=EC=A7=80=EC=A0=95=20=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chore : 빌드 type 지정 에러 해결 --- src/components/layout/sideBar/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/layout/sideBar/index.tsx b/src/components/layout/sideBar/index.tsx index b455c2f..56aafb6 100644 --- a/src/components/layout/sideBar/index.tsx +++ b/src/components/layout/sideBar/index.tsx @@ -34,7 +34,9 @@ const Sidebar: React.FC = () => { - {isModalOpen && } + {isModalOpen && ( + + )} ); }; From 09fdd53fc5123d710fc59caa7903032522725dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 03:02:14 +0900 Subject: [PATCH 11/18] =?UTF-8?q?chore=20:=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chore : 빌드 문제 해결 --- src/models/Modal.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/models/Modal.ts diff --git a/src/models/Modal.ts b/src/models/Modal.ts new file mode 100644 index 0000000..fb6c037 --- /dev/null +++ b/src/models/Modal.ts @@ -0,0 +1,4 @@ +export interface BoardModalProps { + isOpen: boolean; + onClose: () => void; +} From b87bc40db1e3385ba2e515baeb9b7dcc74b8ec37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 03:06:04 +0900 Subject: [PATCH 12/18] Rename Modal.ts to temp.ts --- src/models/{Modal.ts => temp.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/models/{Modal.ts => temp.ts} (100%) diff --git a/src/models/Modal.ts b/src/models/temp.ts similarity index 100% rename from src/models/Modal.ts rename to src/models/temp.ts From 2c916bfa4253e0f710ad2cc8b737a094aee86a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 03:06:26 +0900 Subject: [PATCH 13/18] Rename temp.ts to Modal.ts --- src/models/{temp.ts => Modal.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/models/{temp.ts => Modal.ts} (100%) diff --git a/src/models/temp.ts b/src/models/Modal.ts similarity index 100% rename from src/models/temp.ts rename to src/models/Modal.ts From 1989c21c64ead092a383cb0830e589e190376d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 03:16:02 +0900 Subject: [PATCH 14/18] Rename Modal.ts to temp.ts --- src/models/{Modal.ts => temp.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/models/{Modal.ts => temp.ts} (100%) diff --git a/src/models/Modal.ts b/src/models/temp.ts similarity index 100% rename from src/models/Modal.ts rename to src/models/temp.ts From c0ce3c772f43dac1969d945a431150d2b0de972b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 03:16:20 +0900 Subject: [PATCH 15/18] Rename temp.ts to Modal.ts --- src/models/{temp.ts => Modal.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/models/{temp.ts => Modal.ts} (100%) diff --git a/src/models/temp.ts b/src/models/Modal.ts similarity index 100% rename from src/models/temp.ts rename to src/models/Modal.ts From da1815b9f936d7cd07088c4ba5cc87d2b22290c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 03:24:51 +0900 Subject: [PATCH 16/18] Remove duplicate modal.ts reference --- src/models/modal.ts | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/models/modal.ts diff --git a/src/models/modal.ts b/src/models/modal.ts deleted file mode 100644 index fb6c037..0000000 --- a/src/models/modal.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface BoardModalProps { - isOpen: boolean; - onClose: () => void; -} From 998912dae9622a0d5138ed76aee3e89855d04bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 04:46:39 +0900 Subject: [PATCH 17/18] =?UTF-8?q?style=20:=20=EA=B2=8C=EC=8B=9C=ED=8C=90?= =?UTF-8?q?=20->=20=EC=88=98=EC=97=85=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style : 게시판 -> 수업 이름 변경 --- src/components/modals/AddBoardModal/index.tsx | 8 +++----- src/components/modals/DeleteBoardModal/index.tsx | 11 +++++------ src/components/modals/EditBoardModal/index.tsx | 8 +++----- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/components/modals/AddBoardModal/index.tsx b/src/components/modals/AddBoardModal/index.tsx index a5ec66c..406a0e0 100644 --- a/src/components/modals/AddBoardModal/index.tsx +++ b/src/components/modals/AddBoardModal/index.tsx @@ -52,8 +52,6 @@ const AddBoardModal: React.FC = ({ onClose }) => { }; const handleCreateBoard = () => { - console.log('게시판 이름:', boardName); - console.log('참여자 이메일 목록:', emailList); onClose(); // 모달 닫기 }; @@ -61,13 +59,13 @@ const AddBoardModal: React.FC = ({ onClose }) => { -

게시판 생성하기

+

교실 생성하기

setBoardName(e.target.value)} /> @@ -102,7 +100,7 @@ const AddBoardModal: React.FC = ({ onClose }) => { ))} - 게시판 생성 + 교실 생성
diff --git a/src/components/modals/DeleteBoardModal/index.tsx b/src/components/modals/DeleteBoardModal/index.tsx index 1b0928f..bf20f0b 100644 --- a/src/components/modals/DeleteBoardModal/index.tsx +++ b/src/components/modals/DeleteBoardModal/index.tsx @@ -14,12 +14,11 @@ import { BoardModalProps } from '../../../models/Modal'; const DeleteBoardModal: React.FC = ({ isOpen, onClose }) => { // 더미 데이터 const dummyData = { - boardName: '9oorm_KDT', // 삭제할 게시판 이름 + boardName: '9oorm_KDT', }; // 삭제 버튼 클릭 핸들러 const handleDeleteBoard = () => { - console.log(`게시판 "${dummyData.boardName}"가 삭제되었습니다.`); onClose(); // 모달 닫기 }; if (!isOpen) { @@ -30,20 +29,20 @@ const DeleteBoardModal: React.FC = ({ isOpen, onClose }) => { -

게시판 삭제하기

+

교실 삭제하기

{dummyData.boardName}

- 해당 게시판을 삭제하시겠습니까? + 해당 교실을 삭제하시겠습니까?
- 삭제한 게시판은 복구할 수 없습니다. + 삭제한 교실은 복구할 수 없습니다.

- 게시판 삭제 + 교실 삭제
diff --git a/src/components/modals/EditBoardModal/index.tsx b/src/components/modals/EditBoardModal/index.tsx index d2fde1c..fce5cfd 100644 --- a/src/components/modals/EditBoardModal/index.tsx +++ b/src/components/modals/EditBoardModal/index.tsx @@ -56,8 +56,6 @@ const EditBoardModal: React.FC = ({ isOpen, onClose }) => { }; const handleEditBoard = () => { - console.log('수정된 게시판 이름:', boardName); - console.log('수정된 참여자 이메일 목록:', emailList); onClose(); }; @@ -69,13 +67,13 @@ const EditBoardModal: React.FC = ({ isOpen, onClose }) => { -

게시판 수정하기

+

교실 수정하기

setBoardName(e.target.value)} /> @@ -110,7 +108,7 @@ const EditBoardModal: React.FC = ({ isOpen, onClose }) => { ))} - 게시판 수정 + 교실 수정
From b0263d06192522f0448b2f08b54598b657879862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8A=B9=EC=9A=B0?= Date: Fri, 31 Jan 2025 05:17:26 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat=20:=20email=EC=97=90=EC=84=9C=20id?= =?UTF-8?q?=EB=A1=9C=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD,=20validati?= =?UTF-8?q?on=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat : email에서 id로 로직 변경, validation 삭제 --- src/components/modals/AddBoardModal/index.tsx | 63 ++-- src/components/modals/AddBoardModal/style.ts | 314 +++++++++--------- .../modals/EditBoardModal/index.tsx | 70 ++-- src/components/modals/EditBoardModal/style.ts | 2 +- 4 files changed, 217 insertions(+), 232 deletions(-) diff --git a/src/components/modals/AddBoardModal/index.tsx b/src/components/modals/AddBoardModal/index.tsx index 406a0e0..fc77d71 100644 --- a/src/components/modals/AddBoardModal/index.tsx +++ b/src/components/modals/AddBoardModal/index.tsx @@ -5,7 +5,7 @@ import { ModalHeader, InputFieldWrapper, InputField, - EmailList, + IdList, ButtonWrapper, SubmitButton, Line, @@ -17,38 +17,33 @@ import { BoardModalProps } from '../../../models/Modal'; const AddBoardModal: React.FC = ({ onClose }) => { const [boardName, setBoardName] = useState(''); - const [email, setEmail] = useState(''); - const [emailList, setEmailList] = useState([]); - const [emailError, setEmailError] = useState(false); - const [emailSuccess, setEmailSuccess] = useState(false); - - const validateEmail = (email: string): boolean => { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); - }; + const [id, setId] = useState(''); + const [idList, setIdList] = useState([]); + const [idError, setIdError] = useState(false); + const [idSuccess, setIdSuccess] = useState(false); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { e.preventDefault(); // 기본 엔터 동작 방지 - if (validateEmail(email)) { - if (!emailList.includes(email)) { - setEmailList([...emailList, email]); - setEmailSuccess(true); - setEmailError(false); - setEmail(''); // 입력 초기화 + if (id.trim()) { + if (!idList.includes(id)) { + setIdList([...idList, id]); + setIdSuccess(true); // 성공 메시지 표시 + setIdError(false); // 에러 메시지 제거 + setId(''); // 입력 초기화 } else { - setEmailError(true); - setEmailSuccess(false); + setIdError(true); // 중복된 ID 입력 시 에러 표시 + setIdSuccess(false); // 성공 메시지 제거 } } else { - setEmailError(true); - setEmailSuccess(false); + setIdError(true); // 빈 입력 값에 대한 에러 표시 + setIdSuccess(false); // 성공 메시지 제거 } } }; - const handleRemoveEmail = (targetEmail: string) => { - setEmailList(emailList.filter((item) => item !== targetEmail)); + const handleRemoveId = (targetId: string) => { + setIdList(idList.filter((item) => item !== targetId)); }; const handleCreateBoard = () => { @@ -73,32 +68,30 @@ const AddBoardModal: React.FC = ({ onClose }) => { setEmail(e.target.value)} + placeholder="초대하려는 사용자의 아이디를 입력하세요." + value={id} + onChange={(e) => setId(e.target.value)} onKeyDown={handleKeyDown} style={{ - borderColor: emailError ? 'var(--red)' : 'var(--light-gray)', + borderColor: idError ? 'var(--red)' : 'var(--light-gray)', }} /> - {emailSuccess && ( - 초대가 완료되었습니다. - )} - {emailError && ( - 틀린 이메일이거나 없는 이메일입니다. + {idSuccess && 초대가 완료되었습니다.} + {idError && ( + 틀린 아이디거나 없는 아이디입니다. )} - - {emailList.map((item, index) => ( + + {idList.map((item, index) => (
{item} handleRemoveEmail(item)} + onClick={() => handleRemoveId(item)} />
))} -
+ 교실 생성 diff --git a/src/components/modals/AddBoardModal/style.ts b/src/components/modals/AddBoardModal/style.ts index a741c14..c17f80f 100644 --- a/src/components/modals/AddBoardModal/style.ts +++ b/src/components/modals/AddBoardModal/style.ts @@ -1,190 +1,192 @@ -import styled from "@emotion/styled"; +import styled from '@emotion/styled'; export const ModalOverlay = styled.div` - display: flex; - position: fixed; - top: 0; - left: 7.875rem; - width: 100%; - min-height: 100vh; - background: var(--modal-bg); - justify-content: center; - align-items: center; + display: flex; + position: fixed; + top: 0; + left: 7.875rem; + width: 100%; + min-height: 100vh; + background: var(--modal-bg); + justify-content: center; + align-items: center; `; export const ModalContent = styled.div` - display: flex; - flex-direction: column; - flex-shrink: 0; - border-radius: 0.9375rem; - border: 1px solid var(--gray); - background: var(--background); - padding: 2rem; - box-shadow: 0px 0px 4px 0px var(--light-gray) inset, 0px 0px 4px 0px var(--black); - - h3 { - color: var(--white); - font-family: 'Pretendard'; - font-size: 1.375rem; - font-style: normal; - font-weight: 700; - line-height: normal; - margin-top: 1.69rem; - margin-bottom: 1.06rem; - } + display: flex; + flex-direction: column; + flex-shrink: 0; + border-radius: 0.9375rem; + border: 1px solid var(--gray); + background: var(--background); + padding: 2rem; + box-shadow: + 0px 0px 4px 0px var(--light-gray) inset, + 0px 0px 4px 0px var(--black); + + h3 { + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.375rem; + font-style: normal; + font-weight: 700; + line-height: normal; + margin-top: 1.69rem; + margin-bottom: 1.06rem; + } `; export const ModalHeader = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1.37rem; - - h2 { - color: var(--white); - font-family: 'Pretendard'; - font-size: 1.75rem; - font-style: normal; - font-weight: 700; - line-height: normal; - } - - .CloseButton { - width: 1.5rem; - height: 1.5rem; - flex-shrink: 0; - background: none; - border: none; - cursor: pointer; - color: var(--light-gray); - } + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.37rem; + + h2 { + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.75rem; + font-style: normal; + font-weight: 700; + line-height: normal; + } + + .CloseButton { + width: 1.5rem; + height: 1.5rem; + flex-shrink: 0; + background: none; + border: none; + cursor: pointer; + color: var(--light-gray); + } `; export const Line = styled.div` - width: 100%; - height: 0.125rem; - flex-shrink: 0; - border-radius: 3.125rem; - background-color: var(--gray); - margin-bottom: 1.37rem; + width: 100%; + height: 0.125rem; + flex-shrink: 0; + border-radius: 3.125rem; + background-color: var(--gray); + margin-bottom: 1.37rem; `; export const InputFieldWrapper = styled.div` - position: relative; + position: relative; `; export const InputField = styled.input` - width: 34.875rem; - height: 2rem; - flex-shrink: 0; - background: var(--input); - border-radius: 0.4375rem; - border: 3px solid var(--light-gray); - backdrop-filter: blur(2px); - padding: 0.81rem 1.3rem; - color: var(--white); - font-family: 'Pretendard'; - font-size: 1.125rem; - font-style: normal; - font-weight: 400; - line-height: normal; + width: 34.875rem; + height: 2rem; + flex-shrink: 0; + background: var(--input); + border-radius: 0.4375rem; + border: 3px solid var(--light-gray); + backdrop-filter: blur(2px); + padding: 0.81rem 1.3rem; + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.125rem; + font-style: normal; + font-weight: 400; + line-height: normal; `; export const ErrorMessage = styled.div` - color: var(--red); - text-align: right; - font-family: "Pretendard"; - font-size: 0.625rem; - font-style: normal; - font-weight: 400; - line-height: normal; - position: absolute; - top: -1.5rem; - right: 0; + color: var(--red); + text-align: right; + font-family: 'Pretendard'; + font-size: 0.625rem; + font-style: normal; + font-weight: 400; + line-height: normal; + position: absolute; + top: -1.5rem; + right: 0; `; export const SuccessMessage = styled.div` - color: var(--light-gray); - text-align: right; - font-family: "Pretendard"; - font-size: 0.625rem; - font-style: normal; - font-weight: 400; - line-height: normal; - position: absolute; - top: -1.5rem; - right: 0; + color: var(--light-gray); + text-align: right; + font-family: 'Pretendard'; + font-size: 0.625rem; + font-style: normal; + font-weight: 400; + line-height: normal; + position: absolute; + top: -1.5rem; + right: 0; `; -export const EmailList = styled.div` - display: flex; /* flex container 설정 */ - flex-direction: row; /* 가로 정렬 */ - gap: 0.5rem; /* 아이템 간 간격 */ - flex-wrap: wrap; /* 아이템이 넘칠 경우 줄바꿈 */ - margin-top: 0.88rem; - - .email-item { - width: 10.625rem; - height: 1.75rem; - flex-shrink: 0; - border: 1px solid var(--light-gray); - border-radius: 1.875rem; - background: var(--input); - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.69rem 0.88rem; - color: var(--light-gray); - font-family: "Pretendard"; - font-size: 0.875rem; - font-style: normal; - font-weight: 400; - line-height: normal; - } - - .CloseEmailButton { - width: 0.9375rem; - height: 0.9375rem; - flex-shrink: 0; - background: none; - border: none; - cursor: pointer; - color: var(--light-gray); - font-family: "Pretendard"; - font-size: 0.875rem; - font-style: normal; - font-weight: 400; - line-height: normal; - } -`; +export const IdList = styled.div` + display: flex; /* flex container 설정 */ + flex-direction: row; /* 가로 정렬 */ + gap: 0.5rem; /* 아이템 간 간격 */ + flex-wrap: wrap; /* 아이템이 넘칠 경우 줄바꿈 */ + margin-top: 0.88rem; -export const ButtonWrapper = styled.div` - display: flex; - justify-content: center; - align-items: center; - margin-top: 5.94rem; -`; - -export const SubmitButton = styled.button` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 20.6875rem; - height: 4.0625rem; + .email-item { + width: 10.625rem; + height: 1.75rem; flex-shrink: 0; - border-radius: 0.4375rem; + border: 1px solid var(--light-gray); + border-radius: 1.875rem; background: var(--input); - color: var(--white); + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.69rem 0.88rem; + color: var(--light-gray); font-family: 'Pretendard'; - font-size: 1.25rem; + font-size: 0.875rem; font-style: normal; - font-weight: 700; + font-weight: 400; line-height: normal; + } + + .CloseEmailButton { + width: 0.9375rem; + height: 0.9375rem; + flex-shrink: 0; + background: none; border: none; cursor: pointer; + color: var(--light-gray); + font-family: 'Pretendard'; + font-size: 0.875rem; + font-style: normal; + font-weight: 400; + line-height: normal; + } +`; + +export const ButtonWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + margin-top: 5.94rem; +`; - &:hover { - background: var(--black); - } -`; \ No newline at end of file +export const SubmitButton = styled.button` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 20.6875rem; + height: 4.0625rem; + flex-shrink: 0; + border-radius: 0.4375rem; + background: var(--input); + color: var(--white); + font-family: 'Pretendard'; + font-size: 1.25rem; + font-style: normal; + font-weight: 700; + line-height: normal; + border: none; + cursor: pointer; + + &:hover { + background: var(--black); + } +`; diff --git a/src/components/modals/EditBoardModal/index.tsx b/src/components/modals/EditBoardModal/index.tsx index fce5cfd..321d683 100644 --- a/src/components/modals/EditBoardModal/index.tsx +++ b/src/components/modals/EditBoardModal/index.tsx @@ -5,7 +5,7 @@ import { ModalHeader, InputFieldWrapper, InputField, - EmailList, + IdList, ButtonWrapper, SubmitButton, Line, @@ -18,45 +18,37 @@ import { BoardModalProps } from '../../../models/Modal'; const EditBoardModal: React.FC = ({ isOpen, onClose }) => { // 더미 데이터로 초기값 설정 const [boardName, setBoardName] = useState('9oorm_KDT'); - const [email, setEmail] = useState(''); - const [emailList, setEmailList] = useState([ - 'esder1310@hufs.ac.kr', - 'imi21123@gmail.com', - ]); - const [emailError, setEmailError] = useState(false); - const [emailSuccess, setEmailSuccess] = useState(false); - - const validateEmail = (email: string): boolean => { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); - }; + const [id, setId] = useState(''); + const [idList, setIdList] = useState(['user1', 'user2']); + const [idError, setIdError] = useState(false); + const [idSuccess, setIdSuccess] = useState(false); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { - e.preventDefault(); - if (validateEmail(email)) { - if (!emailList.includes(email)) { - setEmailList([...emailList, email]); - setEmailSuccess(true); - setEmailError(false); - setEmail(''); + e.preventDefault(); // 기본 엔터 동작 방지 + if (id.trim()) { + if (!idList.includes(id)) { + setIdList([...idList, id]); + setIdSuccess(true); // 성공 메시지 표시 + setIdError(false); // 에러 메시지 제거 + setId(''); // 입력 초기화 } else { - setEmailError(true); - setEmailSuccess(false); + setIdError(true); // 중복된 ID 입력 시 에러 표시 + setIdSuccess(false); // 성공 메시지 제거 } } else { - setEmailError(true); - setEmailSuccess(false); + setIdError(true); // 빈 입력 값에 대한 에러 표시 + setIdSuccess(false); // 성공 메시지 제거 } } }; - const handleRemoveEmail = (targetEmail: string) => { - setEmailList(emailList.filter((item) => item !== targetEmail)); + const handleRemoveId = (targetId: string) => { + setIdList(idList.filter((item) => item !== targetId)); }; const handleEditBoard = () => { - onClose(); + onClose(); // 모달 닫기 }; if (!isOpen) { @@ -81,32 +73,30 @@ const EditBoardModal: React.FC = ({ isOpen, onClose }) => { setEmail(e.target.value)} + placeholder="초대하려는 사용자의 아이디를 입력하세요." + value={id} + onChange={(e) => setId(e.target.value)} onKeyDown={handleKeyDown} style={{ - borderColor: emailError ? 'var(--red)' : 'var(--light-gray)', + borderColor: idError ? 'var(--red)' : 'var(--light-gray)', }} /> - {emailSuccess && ( - 초대가 완료되었습니다. - )} - {emailError && ( - 틀린 이메일이거나 없는 이메일입니다. + {idSuccess && 초대가 완료되었습니다.} + {idError && ( + 틀린 아이디거나 없는 아이디입니다.. )} - - {emailList.map((item, index) => ( + + {idList.map((item, index) => (
{item} handleRemoveEmail(item)} + onClick={() => handleRemoveId(item)} />
))} -
+ 교실 수정 diff --git a/src/components/modals/EditBoardModal/style.ts b/src/components/modals/EditBoardModal/style.ts index 3deb3f0..c17f80f 100644 --- a/src/components/modals/EditBoardModal/style.ts +++ b/src/components/modals/EditBoardModal/style.ts @@ -118,7 +118,7 @@ export const SuccessMessage = styled.div` right: 0; `; -export const EmailList = styled.div` +export const IdList = styled.div` display: flex; /* flex container 설정 */ flex-direction: row; /* 가로 정렬 */ gap: 0.5rem; /* 아이템 간 간격 */