Skip to content

Commit 87ac5e7

Browse files
committed
feat: 프로필 수정 기능 추가
1 parent 6fe5225 commit 87ac5e7

File tree

5 files changed

+324
-33
lines changed

5 files changed

+324
-33
lines changed

apps/frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@tanstack/react-query": "^5.59.19",
2525
"@tiptap/extension-collaboration": "^2.9.1",
2626
"@tiptap/extension-collaboration-cursor": "^2.9.1",
27+
"@uiw/react-color": "^2.3.2",
2728
"@xyflow/react": "^12.3.4",
2829
"autoprefixer": "^10.4.20",
2930
"axios": "^1.7.7",
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import logo from "/logo.png?url";
22

3-
export default function LogoBtn() {
3+
interface LogoBtnProps {
4+
onClick?: () => void;
5+
}
6+
export default function LogoBtn({ onClick }: LogoBtnProps) {
47
return (
5-
<div className="h-8 w-8 overflow-clip rounded-md">
8+
<button className="h-8 w-8 overflow-clip rounded-md" onClick={onClick}>
69
<img src={logo} />
7-
</div>
10+
</button>
811
);
912
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { useEffect, useState } from "react";
2+
import Button from "../commons/button";
3+
import { Dialog } from "../commons/dialog";
4+
import { Compact } from "@uiw/react-color";
5+
import useUserStore from "@/store/useUserStore";
6+
7+
type RemoveNoteModalProps = {
8+
isOpen: boolean;
9+
onConfirm: () => void;
10+
onCloseModal: () => void;
11+
};
12+
13+
export default function ProfileModal({
14+
isOpen,
15+
onConfirm,
16+
onCloseModal,
17+
}: RemoveNoteModalProps) {
18+
const { currentUser, setCurrentUser, provider } = useUserStore();
19+
const [hex, setHex] = useState(currentUser.color);
20+
const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);
21+
const [nickname, setNickname] = useState(currentUser.clientId);
22+
23+
useEffect(() => {
24+
setNickname(currentUser.clientId);
25+
setHex(currentUser.color);
26+
}, [currentUser]);
27+
28+
return (
29+
<Dialog isOpen={isOpen} onCloseModal={onCloseModal}>
30+
<div className="flex flex-col items-center gap-4">
31+
<div className="flex flex-col items-center gap-1.5">
32+
<Dialog.Title>프로필 수정</Dialog.Title>
33+
</div>
34+
<div className="flex flex-row items-center gap-3">
35+
<button
36+
className="h-12 w-12 rounded-full border-[1px] border-black"
37+
style={{ backgroundColor: hex }}
38+
onClick={() => setIsColorPickerOpen(!isColorPickerOpen)}
39+
/>
40+
41+
<input
42+
className={
43+
"h-10 rounded-md border-[1px] border-[#eaeaea] p-2 text-sm text-[#141414] outline-none"
44+
}
45+
placeholder="닉네임을 입력하세요"
46+
value={nickname}
47+
onChange={(e) => setNickname(e.target.value)}
48+
/>
49+
</div>
50+
<div className="">
51+
{isColorPickerOpen && (
52+
<Compact color={hex} onChange={(color) => setHex(color.hex)} />
53+
)}
54+
</div>
55+
56+
<div className="flex w-full flex-row justify-between gap-2">
57+
<Button
58+
className="w-full rounded-lg bg-[#171717] text-neutral-100 hover:bg-slate-800"
59+
onClick={() => {
60+
provider.awareness.setLocalStateField("color", hex);
61+
provider.awareness.setLocalStateField("clientId", nickname);
62+
63+
setCurrentUser({
64+
...currentUser,
65+
color: hex,
66+
clientId: nickname,
67+
});
68+
69+
onConfirm();
70+
}}
71+
>
72+
확인
73+
</Button>
74+
<Button
75+
className="w-full rounded-lg bg-[#f4f4f5] text-neutral-700 hover:bg-neutral-200"
76+
onClick={onCloseModal}
77+
>
78+
취소
79+
</Button>
80+
</div>
81+
</div>
82+
<Dialog.CloseButton onCloseModal={onCloseModal} />
83+
</Dialog>
84+
);
85+
}

apps/frontend/src/components/sidebar/TopNav.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
import VerticalDivider from "@/components/commons/divider/VerticalDivider";
22
import WorkspaceNav from "@/components/WorkspaceNav";
33
import LogoBtn from "@/components/LogoBtn";
4-
4+
import ProfileModal from "./ProfileModal";
55
import workspaceLogo from "@/../public/workspace-logo.svg?url";
6+
import { useState } from "react";
67

78
export default function TopNav() {
9+
const [isModalOpen, setIsModalOpen] = useState(false);
10+
811
return (
912
<div className="flex items-center gap-2">
10-
<LogoBtn />
13+
<LogoBtn
14+
onClick={() => {
15+
setIsModalOpen(true);
16+
}}
17+
/>
18+
<ProfileModal
19+
isOpen={isModalOpen}
20+
onCloseModal={() => {
21+
setIsModalOpen(false);
22+
}}
23+
onConfirm={() => {
24+
setIsModalOpen(false);
25+
}}
26+
/>
1127
<VerticalDivider className="h-3" />
1228
<WorkspaceNav imageUrl={workspaceLogo} workspaceTitle="프로젝트 Web15" />
1329
</div>

0 commit comments

Comments
 (0)