Skip to content

Commit

Permalink
Merge pull request #32 from prgrms-web-devcourse-final-project/design…
Browse files Browse the repository at this point in the history
…-프로젝트-미팅룸-#23

[merge/design-프로젝트-미팅룸-#23] Design 프로젝트 미팅룸 #23
  • Loading branch information
sunhyeongpp authored Feb 17, 2025
2 parents 09a38ba + c62dea0 commit ad535c5
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ProjectRoom from "./pages/ProjectRoom/ProjectRoom";
import HeaderLayout from "./components/layout/HeaderLayout";
import ProjectRoomDetail from "./pages/ProjectRoom/ProjectRoomDetail";
import MyPage from "./pages/MyPage";
import MeetingRoom from "./pages/MeetingRoom/MeetingRoom";
import Admin from "./pages/Admin";

const App = () => {
Expand All @@ -31,6 +32,7 @@ const App = () => {
{/* 헤더만 있는 페이지 */}
<Route element={<HeaderLayout />}>
<Route path="/projectRoom" element={<ProjectRoom />} />
<Route path="/meetingRoom/:projectId" element={<MeetingRoom />} />
<Route path="/myPage" element={<MyPage />} />
</Route>
</Routes>
Expand Down
10 changes: 10 additions & 0 deletions src/assets/icons/sendMessage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
156 changes: 156 additions & 0 deletions src/components/MeetingRoom/MeetingRoomChatBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import Button from "../common/Button";
import SendIcon from "../../assets/icons/sendMessage.svg";
import SampleProfile from "../../assets/sample_default_profile.png";
import { useEffect, useRef, useState } from "react";
const MeetingRoomChatBox = () => {
const [text, setText] = useState("");
const [messages, setMessages] = useState<string[]>([]);
const textAreaRef = useRef<HTMLTextAreaElement>(null);
const chatContainerRef = useRef<HTMLDivElement>(null);
const [isComposing, setIsComposing] = useState(false); //조합문자 판별

useEffect(() => {
if (textAreaRef.current) {
textAreaRef.current.style.height = "27px";
}
}, []);

useEffect(() => {
// 메시지가 추가될 때마다 스크롤을 맨 아래로 이동
if (chatContainerRef.current) {
chatContainerRef.current.scrollTop =
chatContainerRef.current.scrollHeight;
}
}, [messages]);

const handleHeight = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const newText = e.target.value;
setText(newText);

if (textAreaRef.current) {
textAreaRef.current.style.height = "27px";
let newHeight = textAreaRef.current.scrollHeight;

if (newHeight > 120) {
newHeight = 120;
textAreaRef.current.style.overflowY = "auto";
} else {
textAreaRef.current.style.overflowY = "hidden";
}

textAreaRef.current.style.height = `${newHeight}px`;

if (chatContainerRef.current) {
chatContainerRef.current.scrollTop =
chatContainerRef.current.scrollHeight;
}
}
};

const handleSendMessage = (e?: React.FormEvent | React.KeyboardEvent) => {
if (e) e.preventDefault();
if (text.trim() === "") return;
setMessages((prevMessages) => [...prevMessages, text]);
setText("");

if (textAreaRef.current) {
textAreaRef.current.style.height = "27px";
}

setTimeout(() => {
if (chatContainerRef.current) {
chatContainerRef.current.scrollTop =
chatContainerRef.current.scrollHeight;
}
}, 100);
};

const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
if (isComposing) return;
e.preventDefault();
handleSendMessage(e);
}
};

return (
<div className="flex flex-col px-[30px] pt-[30px] gap-[10px] relative min-h-full">
<div className="flex justify-between w-[calc(100%-60px)] ">
<span className="font-bold">프로젝트 명</span>
<div className="flex gap-[10px]">
<Button
text="회의록"
size="sm"
css="border-main-green01 bg-white text-main-green01 text-[14px] font-bold"
/>
<Button
text="미팅룸 나가기"
to="/projectRoom"
size="sm"
css="border-header-red bg-header-red/70 text-white text-[14px] font-bold"
/>
</div>
</div>
<div className="flex flex-col flex-grow w-[calc(100%-60px)] gap-[10px]">
<div
ref={chatContainerRef}
className="flex-grow h-0 border-main-green01 bg-white border-[1px] rounded-[10px] overflow-y-auto scrollbar-none "
>
{/* 사용자가 아닐 경우 프로필 사진과 이름 표시 */}
<div className="flex flex-col mx-[10px] pr-[50px] my-[10px] gap-[5px]">
<div className="flex items-center gap-[10px]">
<img
src={SampleProfile}
alt="샘플프로필이미지"
className="w-[30px] h-[30px] rounded-full"
/>
<span className="text-[14px]">사용자이름</span>
</div>
{/* 팀원이 보낸 채팅 내용 bg-main-green02 */}
<div className="w-auto h-auto min-h-[33px] bg-main-green02 rounded-[5px] px-[10px] py-[8px] max-w-[calc(100%-50px)] self-start">
<span className="text-[14px] whitespace-pre-wrap">내용</span>
</div>
</div>
{/* 사용자가 보낸 채팅일 경우 채팅만 표시 bg-main-beige */}
{messages.map((message, index) => (
<div
key={index}
className="flex flex-col mx-[10px] pl-[50px] my-[10px] gap-[5px]"
>
<div className="flex justify-end w-auto h-auto min-h-[33px] bg-main-beige rounded-[5px] px-[10px] py-[8px] max-w-[calc(100%-50px)] self-end">
<span className="text-[14px] whitespace-pre-wrap">
{message}
</span>
</div>
</div>
))}
</div>
<form
onSubmit={handleSendMessage}
className="w-full h-auto flex bg-main-green01 rounded-[10px] pr-[15px] items-center "
>
<textarea
ref={textAreaRef}
value={text}
onChange={handleHeight}
onKeyDown={handleKeyDown}
onCompositionStart={() => setIsComposing(true)}
onCompositionEnd={() => setIsComposing(false)}
className="ml-[15px] mr-[10px] w-full my-[5px] rounded-[5px] bg-white resize-none px-[10px] pt-[5px] pb-[8px] text-[14px] focus:outline-none overflow-y-auto scrollbar-none leading-[17px] placeholder:text-[14px] max-h-[120px] min-h-[27px]"
style={{
height: "27px",
minHeight: "27px",
maxHeight: "120px",
}}
placeholder="채팅 내용을 입력해주세요"
></textarea>
<button type="submit">
<img src={SendIcon} alt="전송버튼" className="cursor-pointer" />
</button>
</form>
</div>
</div>
);
};

export default MeetingRoomChatBox;
30 changes: 30 additions & 0 deletions src/components/MeetingRoom/MeetingRoomProjectBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const MeetingRoomProjectBox = () => {
return (
<div className="flex">
{/* 프로젝트 넘버 */}
<div
className="bg-white border border-[#CAD2CB] w-full h-[70px] flex
gap-5 items-center font-bold "
>
<div className="flex items-center w-full">
<div className="w-[80px] px-[11.5px]">
<span className="text-[50px] text-main-green02 font-notoTC mt-0">
10
</span>
</div>
<div className="flex-grow flex justify-between px-[20px]">
<div className="self-center">
<span className="font-bold">프로젝트 명</span>
</div>
<div className="flex flex-col items-end text-header-red">
<span className="font-bold text-[14px]">새로운 메시지</span>
<span className="font-bold text-[14px]">+99</span>
</div>
</div>
</div>
</div>
</div>
);
};

export default MeetingRoomProjectBox;
4 changes: 3 additions & 1 deletion src/components/ProjectRoom/ProjectListBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ const ProjectListBox = ({ projectId, filterProject }: ProjectListBoxProps) => {
gap-5 items-center px-5 font-bold "
>
{/* 프로젝트 넘버 */}
<p className="text-[50px] font-medium text-main-green02">10</p>
<p className="text-[50px] font-medium text-main-green02 font-notoTC">
10
</p>

<div className="flex justify-between items-center w-full px-5">
{/* 프로젝트 명, 기간 */}
Expand Down
9 changes: 9 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import url('https://fonts.googleapis.com/css2?family=Barlow:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Lacquer&family=Noto+Sans+TC:[email protected]&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
@import "tailwindcss";
@plugin 'tailwind-scrollbar';

Expand All @@ -23,4 +24,12 @@
--color-black01: #212121;
--color-gray01: #AFAFAF;
--color-gray02: #E8E8E8;
--font-notoTC: "Noto Sans TC", "sans-serif";
}


.font-notoTC {
font-family: var(--font-notoTC);
font-weight: 400;
font-style: normal;
}
39 changes: 39 additions & 0 deletions src/pages/MeetingRoom/MeetingRoom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import OutProjectIcon from "../../assets/icons/outProjectDetail.svg";
import MeetingRoomChatBox from "../../components/MeetingRoom/MeetingRoomChatBox";
import MeetingRoomProjectBox from "../../components/MeetingRoom/MeetingRoomProjectBox";

const MeetingRoom = () => {
return (
<div className="flex w-full h-[calc(100vh-50px)] p-[50px] gap-[20px] bg-white bg-gradient-to-t from-white/0 via-[#BFCDB7]/30 to-white/0">
<div className="flex-[0.37] mb-[30px] flex flex-col gap-[30px] px-[30px] bg-white/60">
<div className="ml-[10px]">
<div className="inline-flex flex-col items-center">
<img
src={OutProjectIcon}
alt="프로젝트 나가기"
className="w-[24px] h-[24px]"
/>
<span className="text-main-green01 font-bold">My 프로젝트</span>
</div>
</div>
<div className="w-full h-full flex flex-col gap-[20px] overflow-y-auto scrollbar-none">
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
<MeetingRoomProjectBox />
</div>
</div>
<div className="flex-[0.63] mb-[30px] bg-white/60">
<MeetingRoomChatBox />
</div>
</div>
);
};

export default MeetingRoom;

0 comments on commit ad535c5

Please sign in to comment.